v / vlib / v2 / gen / x64 / x64_backend_runtime_regression_manual_test.v
857 lines · 743 sloc · 15.27 KB · 81a5657604ec6da99c25e26546870c6888d6fdde
Raw
1// vtest build: false
2
3module x64
4
5import os
6
7fn run_x64_backend_runtime_program(name string, source string) string {
8 tmp_dir := os.join_path(os.vtmp_dir(), 'v_x64_backend_runtime_${name}_${os.getpid()}')
9 os.mkdir_all(tmp_dir) or { panic(err) }
10 defer {
11 os.rmdir_all(tmp_dir) or {}
12 }
13 source_path := os.join_path(tmp_dir, '${name}.v')
14 bin_path := os.join_path(tmp_dir, name)
15 os.write_file(source_path, source) or { panic(err) }
16 vexe := os.getenv_opt('VEXE') or { @VEXE }
17 build :=
18 os.execute('${os.quoted_path(vexe)} -v2 -b x64 ${os.quoted_path(source_path)} -o ${os.quoted_path(bin_path)}')
19 assert build.exit_code == 0, build.output
20 run :=
21 os.execute('out=$(${os.quoted_path(bin_path)} 2>&1); code=$?; printf "%s\\n%s" "$code" "$out"')
22 assert run.exit_code == 0, '${name}: ${run.output}'
23 lines := run.output.split_into_lines()
24 assert lines.len >= 1, '${name}: ${run.output}'
25 assert lines[0] == '0', '${name}: ${run.output}'
26 return lines[1..].join('\n')
27}
28
29fn run_x64_backend_runtime_compile_error(name string, source string) string {
30 tmp_dir := os.join_path(os.vtmp_dir(), 'v_x64_backend_runtime_fail_${name}_${os.getpid()}')
31 os.mkdir_all(tmp_dir) or { panic(err) }
32 defer {
33 os.rmdir_all(tmp_dir) or {}
34 }
35 source_path := os.join_path(tmp_dir, '${name}.v')
36 bin_path := os.join_path(tmp_dir, name)
37 os.write_file(source_path, source) or { panic(err) }
38 vexe := os.getenv_opt('VEXE') or { @VEXE }
39 build :=
40 os.execute('${os.quoted_path(vexe)} -v2 -b x64 ${os.quoted_path(source_path)} -o ${os.quoted_path(bin_path)}')
41 assert build.exit_code != 0, build.output
42 return build.output
43}
44
45fn run_x64_backend_runtime_program_redirected(name string, source string) (string, string) {
46 tmp_dir := os.join_path(os.vtmp_dir(), 'v_x64_backend_runtime_redir_${name}_${os.getpid()}')
47 os.mkdir_all(tmp_dir) or { panic(err) }
48 defer {
49 os.rmdir_all(tmp_dir) or {}
50 }
51 source_path := os.join_path(tmp_dir, '${name}.v')
52 bin_path := os.join_path(tmp_dir, name)
53 stdout_path := os.join_path(tmp_dir, '${name}.out')
54 stderr_path := os.join_path(tmp_dir, '${name}.err')
55 os.write_file(source_path, source) or { panic(err) }
56 vexe := os.getenv_opt('VEXE') or { @VEXE }
57 build :=
58 os.execute('${os.quoted_path(vexe)} -v2 -b x64 ${os.quoted_path(source_path)} -o ${os.quoted_path(bin_path)}')
59 assert build.exit_code == 0, build.output
60 run :=
61 os.execute('${os.quoted_path(bin_path)} > ${os.quoted_path(stdout_path)} 2> ${os.quoted_path(stderr_path)}')
62 assert run.exit_code == 0, run.output
63 stdout := os.read_file(stdout_path) or { panic(err) }
64 stderr := os.read_file(stderr_path) or { panic(err) }
65 return stdout, stderr
66}
67
68fn test_x64_backend_runtime_hello_world_runs() {
69 output := run_x64_backend_runtime_program('hello_world', "module main
70
71fn main() {
72 println('Hello World!')
73}
74")
75 assert output == 'Hello World!'
76}
77
78fn test_x64_backend_runtime_hello_world_runs_with_stdout_redirected() {
79 stdout, stderr := run_x64_backend_runtime_program_redirected('hello_world_redir', "module main
80
81fn main() {
82 println('Hello World!')
83}
84")
85 assert stdout == 'Hello World!\n'
86 assert stderr == ''
87}
88
89fn test_x64_backend_runtime_const_init_is_not_skipped() {
90 output := run_x64_backend_runtime_program('const_string', "module main
91
92const greeting = 'Const hello'
93
94fn main() {
95 println(greeting)
96}
97")
98 assert output == 'Const hello'
99}
100
101fn test_x64_backend_runtime_branch_and_local_mutation_pipeline_correctness() {
102 output := run_x64_backend_runtime_program('branch_local_mutation', "module main
103
104fn adjustment(flag bool) int {
105 if flag {
106 return 7
107 }
108 return -3
109}
110
111fn score(a int, b int, flag bool) int {
112 mut total := a * 10
113 total += adjustment(flag)
114 if total > b {
115 return total - b
116 }
117 return b - total
118}
119
120fn main() {
121 if score(4, 35, true) == 12 && score(4, 35, false) == 2 {
122 println('ok')
123 } else {
124 println('bad')
125 }
126}
127")
128 assert output == 'ok'
129}
130
131fn test_x64_backend_runtime_trunc_and_zext_mask_integer_values() {
132 output := run_x64_backend_runtime_program('int_cast_masks', "module main
133
134fn narrow_and_widen(x u16) u64 {
135 y := u8(x)
136 return u64(y)
137}
138
139fn narrow_u32_to_u16(x u32) u64 {
140 y := u16(x)
141 return u64(y)
142}
143
144fn narrow_u64_to_u8(x u64) u64 {
145 y := u8(x)
146 return u64(y)
147}
148
149fn sign_extend_i8(x i8) i64 {
150 return i64(x)
151}
152
153fn sign_extend_i16(x i16) i64 {
154 return i64(x)
155}
156
157fn main() {
158 if narrow_and_widen(u16(0x1234)) == 0x34
159 && narrow_u32_to_u16(u32(0x12345678)) == 0x5678
160 && narrow_u64_to_u8(u64(0x123456789ABCDEFF)) == 0xFF
161 && sign_extend_i8(i8(-42)) == -42
162 && sign_extend_i16(i16(-12345)) == -12345 {
163 println('ok')
164 } else {
165 println('bad')
166 }
167}
168")
169 assert output == 'ok'
170}
171
172fn test_x64_backend_runtime_signed_memory_loads_extend_values() {
173 output := run_x64_backend_runtime_program('signed_memory_loads', "module main
174
175fn load_i8_from_ptr(p &i8) i64 {
176 return i64(*p)
177}
178
179fn load_i16_from_ptr(p &i16) i64 {
180 return i64(*p)
181}
182
183fn main() {
184 mut a := i8(-42)
185 mut b := i16(-12345)
186 if load_i8_from_ptr(&a) == -42 && load_i16_from_ptr(&b) == -12345 {
187 println('ok')
188 } else {
189 println('bad')
190 }
191}
192")
193 assert output == 'ok'
194}
195
196fn test_x64_backend_runtime_raw_copy_tails_do_not_overwrite_sentinel() {
197 output := run_x64_backend_runtime_program('raw_copy_tails', "module main
198
199struct Tiny3 {
200mut:
201 a u8
202 b u8
203 c u8
204}
205
206struct Wrap3 {
207mut:
208 data Tiny3
209 sentinel u8
210}
211
212struct Tiny5 {
213mut:
214 a u8
215 b u8
216 c u8
217 d u8
218 e u8
219}
220
221struct Wrap5 {
222mut:
223 data Tiny5
224 sentinel u8
225}
226
227struct Tiny6 {
228mut:
229 a u8
230 b u8
231 c u8
232 d u8
233 e u8
234 f u8
235}
236
237struct Wrap6 {
238mut:
239 data Tiny6
240 sentinel u8
241}
242
243struct Tiny7 {
244mut:
245 a u8
246 b u8
247 c u8
248 d u8
249 e u8
250 f u8
251 g u8
252}
253
254struct Wrap7 {
255mut:
256 data Tiny7
257 sentinel u8
258}
259
260fn check3() bool {
261 src := Tiny3{
262 a: 1
263 b: 2
264 c: 3
265 }
266 mut w := Wrap3{
267 sentinel: 0x5A
268 }
269 w.data = src
270 return w.sentinel == 0x5A && w.data.a == 1 && w.data.b == 2 && w.data.c == 3
271}
272
273fn check5() bool {
274 src := Tiny5{
275 a: 1
276 b: 2
277 c: 3
278 d: 4
279 e: 5
280 }
281 mut w := Wrap5{
282 sentinel: 0x5A
283 }
284 w.data = src
285 return w.sentinel == 0x5A && w.data.a == 1 && w.data.b == 2 && w.data.c == 3
286 && w.data.d == 4 && w.data.e == 5
287}
288
289fn check6() bool {
290 src := Tiny6{
291 a: 1
292 b: 2
293 c: 3
294 d: 4
295 e: 5
296 f: 6
297 }
298 mut w := Wrap6{
299 sentinel: 0x5A
300 }
301 w.data = src
302 return w.sentinel == 0x5A && w.data.a == 1 && w.data.b == 2 && w.data.c == 3
303 && w.data.d == 4 && w.data.e == 5 && w.data.f == 6
304}
305
306fn check7() bool {
307 src := Tiny7{
308 a: 1
309 b: 2
310 c: 3
311 d: 4
312 e: 5
313 f: 6
314 g: 7
315 }
316 mut w := Wrap7{
317 sentinel: 0x5A
318 }
319 w.data = src
320 return w.sentinel == 0x5A && w.data.a == 1 && w.data.b == 2 && w.data.c == 3
321 && w.data.d == 4 && w.data.e == 5 && w.data.f == 6 && w.data.g == 7
322}
323
324fn main() {
325 if check3() && check5() && check6() && check7() {
326 println('ok')
327 } else {
328 println('bad')
329 }
330}
331")
332 assert output == 'ok'
333}
334
335fn test_x64_backend_runtime_small_aggregates_pass_by_value_in_registers() {
336 output := run_x64_backend_runtime_program('small_aggregate_reg_args', "module main
337
338struct Tiny3 {
339 a u8
340 b u8
341 c u8
342}
343
344struct Tiny5 {
345 a u8
346 b u8
347 c u8
348 d u8
349 e u8
350}
351
352struct Tiny6 {
353 a u8
354 b u8
355 c u8
356 d u8
357 e u8
358 f u8
359}
360
361struct Tiny7 {
362 a u8
363 b u8
364 c u8
365 d u8
366 e u8
367 f u8
368 g u8
369}
370
371fn sum3(t Tiny3) int {
372 return int(t.a) + int(t.b) + int(t.c)
373}
374
375fn sum5(t Tiny5) int {
376 return int(t.a) + int(t.b) + int(t.c) + int(t.d) + int(t.e)
377}
378
379fn sum6(t Tiny6) int {
380 return int(t.a) + int(t.b) + int(t.c) + int(t.d) + int(t.e) + int(t.f)
381}
382
383fn sum7(t Tiny7) int {
384 return int(t.a) + int(t.b) + int(t.c) + int(t.d) + int(t.e) + int(t.f) + int(t.g)
385}
386
387fn main() {
388 a := Tiny3{
389 a: 1
390 b: 2
391 c: 3
392 }
393 b := Tiny5{
394 a: 1
395 b: 2
396 c: 3
397 d: 4
398 e: 5
399 }
400 c := Tiny6{
401 a: 1
402 b: 2
403 c: 3
404 d: 4
405 e: 5
406 f: 6
407 }
408 d := Tiny7{
409 a: 1
410 b: 2
411 c: 3
412 d: 4
413 e: 5
414 f: 6
415 g: 7
416 }
417 if sum3(a) == 6 && sum5(b) == 15 && sum6(c) == 21 && sum7(d) == 28 {
418 println('ok')
419 } else {
420 println('bad')
421 }
422}
423")
424 assert output == 'ok'
425}
426
427fn test_x64_backend_runtime_raw_aggregate_arg_does_not_clobber_rcx_arg() {
428 output := run_x64_backend_runtime_program('small_aggregate_after_rcx_arg', "module main
429
430struct Tiny3 {
431 a u8
432 b u8
433 c u8
434}
435
436fn check(a i64, b i64, c i64, marker i64, t Tiny3) i64 {
437 return marker + i64(t.a) + i64(t.b) + i64(t.c)
438}
439
440fn main() {
441 t := Tiny3{
442 a: 1
443 b: 2
444 c: 3
445 }
446 if check(10, 20, 30, 1000, t) == 1006 {
447 println('ok')
448 } else {
449 println('bad')
450 }
451}
452")
453 assert output == 'ok'
454}
455
456fn test_x64_backend_runtime_big17_sret_and_indirect_param_copy_exact_bytes() {
457 output := run_x64_backend_runtime_program('big17_exact_copies', "module main
458
459struct Big17 {
460mut:
461 a u8
462 b u8
463 c u8
464 d u8
465 e u8
466 f u8
467 g u8
468 h u8
469 i u8
470 j u8
471 k u8
472 l u8
473 m u8
474 n u8
475 o u8
476 p u8
477 q u8
478}
479
480fn make_big() Big17 {
481 return Big17{
482 a: 1
483 b: 2
484 c: 3
485 d: 4
486 e: 5
487 f: 6
488 g: 7
489 h: 8
490 i: 9
491 j: 10
492 k: 11
493 l: 12
494 m: 13
495 n: 14
496 o: 15
497 p: 16
498 q: 17
499 }
500}
501
502fn id_big(x Big17) Big17 {
503 return x
504}
505
506fn sum_big(x Big17) int {
507 return int(x.a) + int(x.b) + int(x.c) + int(x.d) + int(x.e) + int(x.f) + int(x.g)
508 + int(x.h) + int(x.i) + int(x.j) + int(x.k) + int(x.l) + int(x.m) + int(x.n)
509 + int(x.o) + int(x.p) + int(x.q)
510}
511
512fn main() {
513 x := make_big()
514 y := id_big(x)
515 if sum_big(y) == 153 {
516 println('ok')
517 } else {
518 println('bad')
519 }
520}
521")
522 assert output == 'ok'
523}
524
525fn test_x64_backend_runtime_fixed_array_store_uses_raw_copy() {
526 output := run_x64_backend_runtime_program('fixed_array_store', "module main
527
528fn main() {
529 mut src := [3]u8{}
530 src[0] = 1
531 src[1] = 2
532 src[2] = 3
533 mut dst := [3]u8{}
534 dst = src
535 if dst[0] == 1 && dst[1] == 2 && dst[2] == 3 {
536 println('ok')
537 } else {
538 println('bad')
539 }
540}
541")
542 assert output == 'ok'
543}
544
545fn test_x64_backend_runtime_heap_sizing_allows_struct_access_past_eight_bytes() {
546 output := run_x64_backend_runtime_program('heap_struct_size', "module main
547
548struct Heap17 {
549mut:
550 a u8
551 b u8
552 c u8
553 d u8
554 e u8
555 f u8
556 g u8
557 h u8
558 i u8
559 j u8
560 k u8
561 l u8
562 m u8
563 n u8
564 o u8
565 p u8
566 q u8
567}
568
569fn main() {
570 mut p := &Heap17{}
571 p.q = 17
572 if p.q == 17 {
573 println('ok')
574 } else {
575 println('bad')
576 }
577}
578")
579 assert output == 'ok'
580}
581
582fn test_x64_backend_runtime_float_width_casts_convert_values() {
583 output := run_x64_backend_runtime_program('float_width_casts', "module main
584
585fn widen(x f32) f64 {
586 return f64(x)
587}
588
589fn narrow(x f64) f32 {
590 return f32(x)
591}
592
593fn main() {
594 a := widen(f32(1.5))
595 b := narrow(a + 0.25)
596 if a > 1.49 && a < 1.51 && b > f32(1.74) && b < f32(1.76) {
597 println('ok')
598 } else {
599 println('bad')
600 }
601}
602")
603 assert output == 'ok'
604}
605
606fn test_x64_backend_runtime_scalar_float_abi_uses_xmm_registers() {
607 output := run_x64_backend_runtime_program('scalar_float_abi', "module main
608
609fn from_f64_u32(x f64) u32 {
610 return u32(x)
611}
612
613fn id_f64(x f64) f64 {
614 return x
615}
616
617fn id_f32(x f32) f32 {
618 return x
619}
620
621fn mixed(a i64, x f64, b i64, y f32, c i64) i64 {
622 if x > 1.24 && x < 1.26 && y > f32(2.49) && y < f32(2.51) {
623 return a + b + c
624 }
625 return -1
626}
627
628fn main() {
629 x := 4000000000.0
630 local := u32(x) == u32(4000000000)
631 low := from_f64_u32(42.0) == u32(42)
632 high := from_f64_u32(4000000000.0) == u32(4000000000)
633 ret64 := id_f64(1.25) > 1.24 && id_f64(1.25) < 1.26
634 ret32 := id_f32(f32(2.5)) > f32(2.49) && id_f32(f32(2.5)) < f32(2.51)
635 mixed_ok := mixed(10, 1.25, 20, f32(2.5), 30) == 60
636 if local && low && high && ret64 && ret32 && mixed_ok {
637 println('ok')
638 } else {
639 println('bad')
640 }
641}
642")
643 assert output == 'ok'
644}
645
646fn test_x64_backend_runtime_scalar_float_stack_args_fail_explicitly() {
647 output := run_x64_backend_runtime_compile_error('float_stack_arg_unsupported', 'module main
648
649fn many(a f64, b f64, c f64, d f64, e f64, f f64, g f64, h f64, i f64) f64 {
650 return a + b + c + d + e + f + g + h + i
651}
652
653fn main() {
654 _ = many(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
655}
656')
657 assert output.contains('x64: unsupported backend feature: stack-passed float parameter')
658}
659
660fn test_x64_backend_runtime_float_comparisons_use_numeric_semantics() {
661 output := run_x64_backend_runtime_program('float_comparisons', "module main
662
663import os
664
665fn eq_f64(a f64, b f64) bool {
666 return a == b
667}
668
669fn ne_f64(a f64, b f64) bool {
670 return a != b
671}
672
673fn lt_f64(a f64, b f64) bool {
674 return a < b
675}
676
677fn gt_f64(a f64, b f64) bool {
678 return a > b
679}
680
681fn le_f64(a f64, b f64) bool {
682 return a <= b
683}
684
685fn ge_f64(a f64, b f64) bool {
686 return a >= b
687}
688
689fn le_f32(a f32, b f32) bool {
690 return a <= b
691}
692
693fn gt_f32(a f32, b f32) bool {
694 return a > b
695}
696
697fn ge_f32(a f32, b f32) bool {
698 return a >= b
699}
700
701fn eq_f32(a f32, b f32) bool {
702 return a == b
703}
704
705fn ne_f32(a f32, b f32) bool {
706 return a != b
707}
708
709fn lt_f32(a f32, b f32) bool {
710 return a < b
711}
712
713fn main() {
714 argc := os.args.len
715 z := f64(argc - argc)
716 one := f64(argc)
717 two := one + one
718 neg_zero := -z
719 nan := z / z
720 ok64 := eq_f64(z, neg_zero) && ne_f64(nan, nan) && lt_f64(-two, -one)
721 && gt_f64(-one, -two) && le_f64(z, neg_zero) && ge_f64(z, neg_zero)
722 nan64 := !eq_f64(nan, nan) && ne_f64(nan, nan) && !lt_f64(nan, one)
723 && !le_f64(nan, one) && !gt_f64(nan, one) && !ge_f64(nan, one)
724 nanf := f32(nan)
725 onef := f32(one)
726 ok32 := eq_f32(f32(z), f32(neg_zero)) && lt_f32(f32(-two), f32(-one))
727 nan32 := !eq_f32(nanf, nanf) && ne_f32(nanf, nanf) && !lt_f32(nanf, onef)
728 && !le_f32(nanf, onef) && !gt_f32(nanf, onef) && !ge_f32(nanf, onef)
729 if ok64 && nan64 && ok32 && nan32 {
730 println('ok')
731 } else {
732 println('bad')
733 }
734}
735")
736 assert output == 'ok'
737}
738
739fn test_x64_backend_runtime_unsigned_64_to_float_handles_high_bit() {
740 output := run_x64_backend_runtime_program('u64_to_float_high_bit', "module main
741
742fn to_f64(x u64) f64 {
743 return f64(x)
744}
745
746fn to_f32(x u64) f32 {
747 return f32(x)
748}
749
750fn main() {
751 a := to_f64(u64(9223372036854775808))
752 b := to_f64(u64(18446744073709551615))
753 c := to_f32(u64(9223372036854775808))
754 if a == 9223372036854775808.0 && b > 18446744073709550000.0 && c > f32(9223371000000000000.0) {
755 println('ok')
756 } else {
757 println('bad')
758 }
759}
760")
761 assert output == 'ok'
762}
763
764fn test_x64_backend_runtime_float_to_unsigned_64_handles_high_bit() {
765 output := run_x64_backend_runtime_program('float_to_u64_high_bit', "module main
766
767fn from_f64(x f64) u64 {
768 return u64(x)
769}
770
771fn from_f32(x f32) u64 {
772 return u64(x)
773}
774
775fn main() {
776 a := from_f64(9223372036854775808.0)
777 b := from_f64(9223372036854777856.0)
778 c := from_f32(f32(9223372036854775808.0))
779 if a == u64(9223372036854775808) && b == u64(9223372036854777856)
780 && c == u64(9223372036854775808) {
781 println('ok')
782 } else {
783 println('bad')
784 }
785}
786")
787 assert output == 'ok'
788}
789
790fn test_x64_backend_runtime_aggregate_arg_spills_to_stack() {
791 output := run_x64_backend_runtime_program('aggregate_arg_spill', "module main
792
793struct Pair {
794 a i64
795 b i64
796}
797
798fn sum_after_five(a i64, b i64, c i64, d i64, e i64, p Pair) i64 {
799 return a + b + c + d + e + p.a + p.b
800}
801
802fn main() {
803 if sum_after_five(1, 2, 3, 4, 5, Pair{6, 7}) == 28 {
804 println('ok')
805 } else {
806 println('bad')
807 }
808}
809")
810 assert output == 'ok'
811}
812
813fn test_x64_backend_runtime_stack_arg_after_two_chunk_aggregate() {
814 output := run_x64_backend_runtime_program('stack_arg_after_pair', "module main
815
816struct Pair {
817 a i64
818 b i64
819}
820
821fn sum_pair_then_scalars(p Pair, a i64, b i64, c i64, d i64, e i64) i64 {
822 return p.a + p.b + a + b + c + d + e
823}
824
825fn main() {
826 if sum_pair_then_scalars(Pair{10, 20}, 1, 2, 3, 4, 5) == 45 {
827 println('ok')
828 } else {
829 println('bad')
830 }
831}
832")
833 assert output == 'ok'
834}
835
836fn test_x64_backend_runtime_spilled_aggregate_does_not_consume_remaining_register() {
837 output := run_x64_backend_runtime_program('aggregate_spill_then_reg', "module main
838
839struct Pair {
840 a i64
841 b i64
842}
843
844fn sum_spill_then_reg(a i64, b i64, c i64, d i64, e i64, p Pair, z i64) i64 {
845 return p.a + p.b + z
846}
847
848fn main() {
849 if sum_spill_then_reg(1, 2, 3, 4, 5, Pair{10, 20}, 6) == 36 {
850 println('ok')
851 } else {
852 println('bad')
853 }
854}
855")
856 assert output == 'ok'
857}
858