lib/va_list.c: - Handle struct {double, double} correctly arm64-gen.c: riscv64-gen.c: x86_64-gen.c: - Allow zero sized structs to work with va_arg tcctest.c: - Add new va_arg test code test/bug.c: - Remove tst2 va_arg test
Unified · Split
| @@ -1050,10 +1050,12 @@ ST_FUNC void gfunc_call(int nb_args) · 1049 unmodified lines | |||
| 1050 | // value in general-purpose registers | 1050 | // value in general-purpose registers |
| 1051 | if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { | 1051 | if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
| 1052 | int align, size = type_size(&vtop->type, &align); | 1052 | int align, size = type_size(&vtop->type, &align); |
| 1053 | vtop->type.t = VT_PTR; | 1053 | if (size) { |
| 1054 | gaddrof(); | 1054 | vtop->type.t = VT_PTR; |
| 1055 | gv(RC_R(a[i] / 2)); | 1055 | gaddrof(); |
| 1056 | arm64_ldrs(a[i] / 2, size); | 1056 | gv(RC_R(a[i] / 2)); |
| 1057 | arm64_ldrs(a[i] / 2, size); | ||
| 1058 | } | ||
| 1057 | } | 1059 | } |
| 1058 | else | 1060 | else |
| 1059 | gv(RC_R(a[i] / 2)); | 1061 | gv(RC_R(a[i] / 2)); |
| @@ -23,6 +23,8 @@ typedef struct { · 22 unmodified lines | |||
| 23 | } __builtin_va_list[1]; | 23 | } __builtin_va_list[1]; |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | extern void *memcpy(void *dest, const void *src, unsigned long n); | ||
| 27 | |||
| 26 | void *__va_arg(__builtin_va_list ap, | 28 | void *__va_arg(__builtin_va_list ap, |
| 27 | int arg_type, | 29 | int arg_type, |
| 28 | int size, int align) | 30 | int size, int align) |
| @@ -40,9 +42,15 @@ void *__va_arg(__builtin_va_list ap, · 11 unmodified lines | |||
| 40 | case __va_float_reg: | 42 | case __va_float_reg: |
| 41 | if (ap->fp_offset < 128 + 48) { | 43 | if (ap->fp_offset < 128 + 48) { |
| 42 | ap->fp_offset += 16; | 44 | ap->fp_offset += 16; |
| 43 | return ap->reg_save_area + ap->fp_offset - 16; | 45 | if (size == 8) |
| 46 | return ap->reg_save_area + ap->fp_offset - 16; | ||
| 47 | if (ap->fp_offset < 128 + 48) { | ||
| 48 | memcpy(ap->reg_save_area + ap->fp_offset - 8, | ||
| 49 | ap->reg_save_area + ap->fp_offset, 8); | ||
| 50 | ap->fp_offset += 16; | ||
| 51 | return ap->reg_save_area + ap->fp_offset - 32; | ||
| 52 | } | ||
| 44 | } | 53 | } |
| 45 | size = 8; | ||
| 46 | goto use_overflow_area; | 54 | goto use_overflow_area; |
| 47 | 55 | ||
| 48 | case __va_stack: | 56 | case __va_stack: |
| @@ -552,7 +552,9 @@ ST_FUNC void gfunc_call(int nb_args) · 551 unmodified lines | |||
| 552 | if (!sa && align == 2*XLEN && size <= 2*XLEN) | 552 | if (!sa && align == 2*XLEN && size <= 2*XLEN) |
| 553 | areg[0] = (areg[0] + 1) & ~1; | 553 | areg[0] = (areg[0] + 1) & ~1; |
| 554 | nregs = prc[0]; | 554 | nregs = prc[0]; |
| 555 | if ((prc[1] == RC_INT && areg[0] >= 8) | 555 | if (size == 0) |
| 556 | info[i] = 0; | ||
| 557 | else if ((prc[1] == RC_INT && areg[0] >= 8) | ||
| 556 | || (prc[1] == RC_FLOAT && areg[1] >= 16) | 558 | || (prc[1] == RC_FLOAT && areg[1] >= 16) |
| 557 | || (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT | 559 | || (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT |
| 558 | && areg[1] >= 15) | 560 | && areg[1] >= 15) |
| @@ -651,6 +653,8 @@ ST_FUNC void gfunc_call(int nb_args) · 92 unmodified lines | |||
| 651 | vrotb(i+1); | 653 | vrotb(i+1); |
| 652 | origtype = vtop->type; | 654 | origtype = vtop->type; |
| 653 | size = type_size(&vtop->type, &align); | 655 | size = type_size(&vtop->type, &align); |
| 656 | if (size == 0) | ||
| 657 | goto done; | ||
| 654 | loadt = vtop->type.t & VT_BTYPE; | 658 | loadt = vtop->type.t & VT_BTYPE; |
| 655 | if (loadt == VT_STRUCT) { | 659 | if (loadt == VT_STRUCT) { |
| 656 | loadt = (ii >> 12) & VT_BTYPE; | 660 | loadt = (ii >> 12) & VT_BTYPE; |
| @@ -701,6 +705,7 @@ ST_FUNC void gfunc_call(int nb_args) · 44 unmodified lines | |||
| 701 | EI(0x13, 0, ireg(r2), ireg(vtop->r2), 0); // mv Ra+1, RR2 | 705 | EI(0x13, 0, ireg(r2), ireg(vtop->r2), 0); // mv Ra+1, RR2 |
| 702 | vtop->r2 = r2; | 706 | vtop->r2 = r2; |
| 703 | } | 707 | } |
| 708 | done: | ||
| 704 | vrott(i+1); | 709 | vrott(i+1); |
| 705 | } | 710 | } |
| 706 | } | 711 | } |
| @@ -1,21 +1,6 @@ | |||
| 1 | #include <stdio.h> | 1 | #include <stdio.h> |
| 2 | #include <stdarg.h> | 2 | #include <stdarg.h> |
| 3 | 3 | ||
| 4 | typedef struct{double x,y;}p; | ||
| 5 | |||
| 6 | void tst2(int n,...) | ||
| 7 | { | ||
| 8 | /* va_arg for struct double does not work on some targets */ | ||
| 9 | int i; | ||
| 10 | va_list args; | ||
| 11 | va_start(args,n); | ||
| 12 | for (i = 0; i < n; i++) { | ||
| 13 | p v = va_arg(args,p); | ||
| 14 | if (v.x != 1 || v.y != 2) printf("%g %g\n", v.x, v.y); | ||
| 15 | } | ||
| 16 | va_end(args); | ||
| 17 | } | ||
| 18 | |||
| 19 | void tst3(void) | 4 | void tst3(void) |
| 20 | { | 5 | { |
| 21 | /* Should VT_SYM be checked for TOK_builtin_constant_p */ | 6 | /* Should VT_SYM be checked for TOK_builtin_constant_p */ |
| @@ -60,7 +45,5 @@ int compile_errors(void) · 38 unmodified lines | |||
| 60 | int | 45 | int |
| 61 | main(void) | 46 | main(void) |
| 62 | { | 47 | { |
| 63 | p v = { 1, 2}; | ||
| 64 | tst2(1, v); | ||
| 65 | tst3(); | 48 | tst3(); |
| 66 | } | 49 | } |
| @@ -2627,18 +2627,34 @@ void vprintf1(const char *fmt, ...) · 2626 unmodified lines | |||
| 2627 | struct myspace { | 2627 | struct myspace { |
| 2628 | short int profile; | 2628 | short int profile; |
| 2629 | }; | 2629 | }; |
| 2630 | struct myspace2 { | ||
| 2631 | char a[0]; | ||
| 2632 | }; | ||
| 2633 | struct myspace3 { | ||
| 2634 | char a[1]; | ||
| 2635 | }; | ||
| 2636 | struct myspace4 { | ||
| 2637 | char a[2]; | ||
| 2638 | }; | ||
| 2630 | 2639 | ||
| 2631 | void stdarg_for_struct(struct myspace bob, ...) | 2640 | void stdarg_for_struct(struct myspace bob, ...) |
| 2632 | { | 2641 | { |
| 2633 | struct myspace george, bill; | 2642 | struct myspace george, bill; |
| 2643 | struct myspace2 alex1; | ||
| 2644 | struct myspace3 alex2; | ||
| 2645 | struct myspace4 alex3; | ||
| 2634 | va_list ap; | 2646 | va_list ap; |
| 2635 | short int validate; | 2647 | short int validate; |
| 2636 | 2648 | ||
| 2637 | va_start(ap, bob); | 2649 | va_start(ap, bob); |
| 2650 | alex1 = va_arg(ap, struct myspace2); | ||
| 2651 | alex2 = va_arg(ap, struct myspace3); | ||
| 2652 | alex3 = va_arg(ap, struct myspace4); | ||
| 2638 | bill = va_arg(ap, struct myspace); | 2653 | bill = va_arg(ap, struct myspace); |
| 2639 | george = va_arg(ap, struct myspace); | 2654 | george = va_arg(ap, struct myspace); |
| 2640 | validate = va_arg(ap, int); | 2655 | validate = va_arg(ap, int); |
| 2641 | printf("stdarg_for_struct: %d %d %d %d\n", | 2656 | printf("stdarg_for_struct: %d %d %d %d %d %d %d\n", |
| 2657 | alex2.a[0], alex3.a[0], alex3.a[1], | ||
| 2642 | bob.profile, bill.profile, george.profile, validate); | 2658 | bob.profile, bill.profile, george.profile, validate); |
| 2643 | va_end(ap); | 2659 | va_end(ap); |
| 2644 | } | 2660 | } |
| @@ -2664,10 +2680,40 @@ void stdarg_syntax(int n, ...) · 19 unmodified lines | |||
| 2664 | (va_end(ap)); | 2680 | (va_end(ap)); |
| 2665 | } | 2681 | } |
| 2666 | 2682 | ||
| 2683 | typedef struct{ | ||
| 2684 | double x,y; | ||
| 2685 | } point; | ||
| 2686 | point pts[]={{1.0,2.0},{3.0,4.0},{5.0,6.0},{7.0,8.0},{9.0,10.0},{11.0,12.0}}; | ||
| 2687 | |||
| 2688 | static void stdarg_double_struct(int nargs, int posd,...) | ||
| 2689 | { | ||
| 2690 | int i; | ||
| 2691 | double d; | ||
| 2692 | point pi; | ||
| 2693 | va_list args; | ||
| 2694 | |||
| 2695 | printf ("stdarg_double_struct: %d\n", posd); | ||
| 2696 | va_start(args,posd); | ||
| 2697 | for(i = 0; i < nargs; i++) { | ||
| 2698 | if (i == posd) { | ||
| 2699 | d = va_arg (args, double); | ||
| 2700 | printf ("d %d = %g\n", i, d); | ||
| 2701 | } | ||
| 2702 | else { | ||
| 2703 | pi = va_arg (args, point); | ||
| 2704 | printf ("pts[%d] = %g %g\n", i, pi.x, pi.y); | ||
| 2705 | } | ||
| 2706 | } | ||
| 2707 | va_end(args); | ||
| 2708 | } | ||
| 2709 | |||
| 2667 | void stdarg_test(void) | 2710 | void stdarg_test(void) |
| 2668 | { | 2711 | { |
| 2669 | LONG_DOUBLE ld = 1234567891234LL; | 2712 | LONG_DOUBLE ld = 1234567891234LL; |
| 2670 | struct myspace bob; | 2713 | struct myspace bob; |
| 2714 | struct myspace2 bob2; | ||
| 2715 | struct myspace3 bob3; | ||
| 2716 | struct myspace4 bob4; | ||
| 2671 | 2717 | ||
| 2672 | vprintf1("%d %d %d\n", 1, 2, 3); | 2718 | vprintf1("%d %d %d\n", 1, 2, 3); |
| 2673 | vprintf1("%f %d %f\n", 1.0, 2, 3.0); | 2719 | vprintf1("%f %d %f\n", 1.0, 2, 3.0); |
| @@ -2709,9 +2755,20 @@ void stdarg_test(void) · 35 unmodified lines | |||
| 2709 | 42.0, 43.0, ld); | 2755 | 42.0, 43.0, ld); |
| 2710 | 2756 | ||
| 2711 | bob.profile = 42; | 2757 | bob.profile = 42; |
| 2712 | stdarg_for_struct(bob, bob, bob, bob.profile); | 2758 | bob3.a[0] = 1; |
| 2759 | bob4.a[0] = 2; | ||
| 2760 | bob4.a[1] = 3; | ||
| 2761 | stdarg_for_struct(bob, bob2, bob3, bob4, bob, bob, bob.profile); | ||
| 2713 | stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); | 2762 | stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); |
| 2714 | stdarg_syntax(1, 17); | 2763 | stdarg_syntax(1, 17); |
| 2764 | #ifndef __riscv | ||
| 2765 | stdarg_double_struct(6,-1,pts[0],pts[1],pts[2],pts[3],pts[4],pts[5]); | ||
| 2766 | stdarg_double_struct(7,1,pts[0],-1.0,pts[1],pts[2],pts[3],pts[4],pts[5]); | ||
| 2767 | stdarg_double_struct(7,2,pts[0],pts[1],-1.0,pts[2],pts[3],pts[4],pts[5]); | ||
| 2768 | stdarg_double_struct(7,3,pts[0],pts[1],pts[2],-1.0,pts[3],pts[4],pts[5]); | ||
| 2769 | stdarg_double_struct(7,4,pts[0],pts[1],pts[2],pts[3],-1.0,pts[4],pts[5]); | ||
| 2770 | stdarg_double_struct(7,5,pts[0],pts[1],pts[2],pts[3],pts[4],-1.0,pts[5]); | ||
| 2771 | #endif | ||
| 2715 | } | 2772 | } |
| 2716 | 2773 | ||
| 2717 | int reltab[3] = { 1, 2, 3 }; | 2774 | int reltab[3] = { 1, 2, 3 }; |
| @@ -1244,6 +1244,7 @@ void gfunc_call(int nb_args) · 1243 unmodified lines | |||
| 1244 | stack_adjust = 0; | 1244 | stack_adjust = 0; |
| 1245 | for(i = nb_args - 1; i >= 0; i--) { | 1245 | for(i = nb_args - 1; i >= 0; i--) { |
| 1246 | mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); | 1246 | mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); |
| 1247 | if (size == 0) continue; | ||
| 1247 | if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) { | 1248 | if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) { |
| 1248 | nb_sse_args += reg_count; | 1249 | nb_sse_args += reg_count; |
| 1249 | onstack[i] = 0; | 1250 | onstack[i] = 0; |
| @@ -1278,21 +1279,23 @@ void gfunc_call(int nb_args) · 28 unmodified lines | |||
| 1278 | stack_adjust &= 15; | 1279 | stack_adjust &= 15; |
| 1279 | for (i = k = 0; i < nb_args;) { | 1280 | for (i = k = 0; i < nb_args;) { |
| 1280 | mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); | 1281 | mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); |
| 1281 | if (!onstack[i + k]) { | 1282 | if (size) { |
| 1282 | ++i; | 1283 | if (!onstack[i + k]) { |
| 1283 | continue; | 1284 | ++i; |
| 1284 | } | 1285 | continue; |
| 1285 | /* Possibly adjust stack to align SSE boundary. We're processing | 1286 | } |
| 1286 | args from right to left while allocating happens left to right | 1287 | /* Possibly adjust stack to align SSE boundary. We're processing |
| 1287 | (stack grows down), so the adjustment needs to happen _after_ | 1288 | args from right to left while allocating happens left to right |
| 1288 | an argument that requires it. */ | 1289 | (stack grows down), so the adjustment needs to happen _after_ |
| 1289 | if (stack_adjust) { | 1290 | an argument that requires it. */ |
| 1290 | o(0x50); /* push %rax; aka sub $8,%rsp */ | 1291 | if (stack_adjust) { |
| 1291 | args_size += 8; | 1292 | o(0x50); /* push %rax; aka sub $8,%rsp */ |
| 1292 | stack_adjust = 0; | 1293 | args_size += 8; |
| 1294 | stack_adjust = 0; | ||
| 1295 | } | ||
| 1296 | if (onstack[i + k] == 2) | ||
| 1297 | stack_adjust = 1; | ||
| 1293 | } | 1298 | } |
| 1294 | if (onstack[i + k] == 2) | ||
| 1295 | stack_adjust = 1; | ||
| 1296 | 1299 | ||
| 1297 | vrotb(i+1); | 1300 | vrotb(i+1); |
| 1298 | 1301 | ||
| @@ -1357,6 +1360,7 @@ void gfunc_call(int nb_args) · 58 unmodified lines | |||
| 1357 | assert(sse_reg <= 8); | 1360 | assert(sse_reg <= 8); |
| 1358 | for(i = 0; i < nb_args; i++) { | 1361 | for(i = 0; i < nb_args; i++) { |
| 1359 | mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); | 1362 | mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); |
| 1363 | if (size == 0) continue; | ||
| 1360 | /* Alter stack entry type so that gv() knows how to treat it */ | 1364 | /* Alter stack entry type so that gv() knows how to treat it */ |
| 1361 | vtop->type = type; | 1365 | vtop->type = type; |
| 1362 | if (mode == x86_64_mode_sse) { | 1366 | if (mode == x86_64_mode_sse) { |