History

tcc -freverse-funcargs (reverse evaluation)

patch originally made to prove correctness (comparing stages) with tinycc compiling gcc 2.95.3 which would assign registers differently (but still correctly) when compiled with tcc without this option). Also: fixes get_temp_local_var() which on 32-bit systems happened to return a temporary location that was still in use because its offset was changed on the vstack (incremented by four in gv() to load the second register of a long long).

grischka committed 1 year ago

Commit f24727b1 parent c717bac6 files · +112 −81Browse files

Unified · Split

6 files
  1. libtcc.c +1 −0
  2. tcc.c +1 −0
  3. tcc.h +2 −1
  4. tccgen.c +91 −79
  5. tests/tests2/60_errors_and_warnings.c +10 −0
  6. tests/tests2/60_errors_and_warnings.expect +7 −1
libtcc.c+1−0
@@ -1673,6 +1673,7 @@ static const FlagDef options_f[] = { · 1672 unmodified lines
1673 { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },1673 { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
1674 { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },1674 { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
1675 { offsetof(TCCState, test_coverage), 0, "test-coverage" },1675 { offsetof(TCCState, test_coverage), 0, "test-coverage" },
1676 { offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs" },
1676 { 0, 0, NULL }1677 { 0, 0, NULL }
1677};1678};
1678 1679
tcc.c+1−0
@@ -115,6 +115,7 @@ static const char help2[] = · 114 unmodified lines
115 " leading-underscore decorate extern symbols\n"115 " leading-underscore decorate extern symbols\n"
116 " ms-extensions allow anonymous struct in struct\n"116 " ms-extensions allow anonymous struct in struct\n"
117 " dollars-in-identifiers allow '$' in C symbols\n"117 " dollars-in-identifiers allow '$' in C symbols\n"
118 " reverse-funcargs evaluate function arguments right to left\n"
118 " test-coverage create code coverage code\n"119 " test-coverage create code coverage code\n"
119 "-m... target specific options:\n"120 "-m... target specific options:\n"
120 " ms-bitfields use MSVC bitfield layout\n"121 " ms-bitfields use MSVC bitfield layout\n"
tcc.h+2−1
@@ -776,6 +776,7 @@ struct TCCState { · 775 unmodified lines
776 unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */776 unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
777 unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */777 unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */
778 unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */778 unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
779 unsigned char reverse_funcargs; /* if true, evaluate last function arg first */
779 780
780 /* warning switches */781 /* warning switches */
781 unsigned char warn_none;782 unsigned char warn_none;
@@ -1490,9 +1491,9 @@ ST_FUNC void vpushi(int v); · 708 unmodified lines
1490ST_FUNC void vpushv(SValue *v);1491ST_FUNC void vpushv(SValue *v);
1491ST_FUNC void vpushsym(CType *type, Sym *sym);1492ST_FUNC void vpushsym(CType *type, Sym *sym);
1492ST_FUNC void vswap(void);1493ST_FUNC void vswap(void);
1493ST_FUNC void vrote(SValue *e, int n);
1494ST_FUNC void vrott(int n);1494ST_FUNC void vrott(int n);
1495ST_FUNC void vrotb(int n);1495ST_FUNC void vrotb(int n);
1496ST_FUNC void vrev(int n);
1496ST_FUNC void vpop(void);1497ST_FUNC void vpop(void);
1497#if PTR_SIZE == 41498#if PTR_SIZE == 4
1498ST_FUNC void lexpand(void);1499ST_FUNC void lexpand(void);
tccgen.c+91−79
@@ -154,8 +154,7 @@ static void gen_inline_functions(TCCState *s); · 153 unmodified lines
154static void free_inline_functions(TCCState *s);154static void free_inline_functions(TCCState *s);
155static void skip_or_save_block(TokenString **str);155static void skip_or_save_block(TokenString **str);
156static void gv_dup(void);156static void gv_dup(void);
157static int get_temp_local_var(int size,int align);157static int get_temp_local_var(int size,int align,int *r2);
158static void clear_temp_local_var_list();
159static void cast_error(CType *st, CType *dt);158static void cast_error(CType *st, CType *dt);
160static void end_switch(void);159static void end_switch(void);
161 160
@@ -957,42 +956,38 @@ static void vdup(void) · 795 unmodified lines
957 vpushv(vtop);956 vpushv(vtop);
958}957}
959 958
960/* rotate n first stack elements to the bottom959/* rotate the stack element at position n-1 to the top */
961 I1 ... In -> I2 ... In I1 [top is right]
962*/
963ST_FUNC void vrotb(int n)960ST_FUNC void vrotb(int n)
964{961{
965 int i;
966 SValue tmp;962 SValue tmp;
967 963 if (--n < 1)
964 return;
968 vcheck_cmp();965 vcheck_cmp();
969 tmp = vtop[-n + 1];966 tmp = vtop[-n];
970 for(i=-n+1;i!=0;i++)967 memmove(vtop - n, vtop - n + 1, sizeof *vtop * n);
971 vtop[i] = vtop[i+1];
972 vtop[0] = tmp;968 vtop[0] = tmp;
973}969}
974 970
975/* rotate the n elements before entry e towards the top971/* rotate the top stack element into position n-1 */
976 I1 ... In ... -> In I1 ... I(n-1) ... [top is right]972ST_FUNC void vrott(int n)
977 */
978ST_FUNC void vrote(SValue *e, int n)
979{973{
980 int i;
981 SValue tmp;974 SValue tmp;
982 975 if (--n < 1)
976 return;
983 vcheck_cmp();977 vcheck_cmp();
984 tmp = *e;978 tmp = vtop[0];
985 for(i = 0;i < n - 1; i++)979 memmove(vtop - n + 1, vtop - n, sizeof *vtop * n);
986 e[-i] = e[-i - 1];980 vtop[-n] = tmp;
987 e[-n + 1] = tmp;
988}981}
989 982
990/* rotate n first stack elements to the top983/* reverse order of the the first n stack elements */
991 I1 ... In -> In I1 ... I(n-1) [top is right]984ST_FUNC void vrev(int n)
992 */
993ST_FUNC void vrott(int n)
994{985{
995 vrote(vtop, n);986 int i;
987 SValue tmp;
988 vcheck_cmp();
989 for (i = 0, n = -n; i > ++n; --i)
990 tmp = vtop[i], vtop[i] = vtop[n], vtop[n] = tmp;
996}991}
997 992
998/* ------------------------------------------------------------------------- */993/* ------------------------------------------------------------------------- */
@@ -1354,14 +1349,14 @@ ST_FUNC void save_reg(int r) · 355 unmodified lines
1354 if seen up to (vtop - n) stack entry */1349 if seen up to (vtop - n) stack entry */
1355ST_FUNC void save_reg_upstack(int r, int n)1350ST_FUNC void save_reg_upstack(int r, int n)
1356{1351{
1357 int l, size, align, bt;1352 int l, size, align, bt, r2;
1358 SValue *p, *p1, sv;1353 SValue *p, *p1, sv;
1359 1354
1360 if ((r &= VT_VALMASK) >= VT_CONST)1355 if ((r &= VT_VALMASK) >= VT_CONST)
1361 return;1356 return;
1362 if (nocode_wanted)1357 if (nocode_wanted)
1363 return;1358 return;
1364 l = 0;1359 l = r2 = 0;
1365 for(p = vstack, p1 = vtop - n; p <= p1; p++) {1360 for(p = vstack, p1 = vtop - n; p <= p1; p++) {
1366 if ((p->r & VT_VALMASK) == r || p->r2 == r) {1361 if ((p->r & VT_VALMASK) == r || p->r2 == r) {
1367 /* must save value on stack if not already done */1362 /* must save value on stack if not already done */
@@ -1373,7 +1368,7 @@ ST_FUNC void save_reg_upstack(int r, int n) · 5 unmodified lines
1373 bt = VT_PTR;1368 bt = VT_PTR;
1374 sv.type.t = bt;1369 sv.type.t = bt;
1375 size = type_size(&sv.type, &align);1370 size = type_size(&sv.type, &align);
1376 l = get_temp_local_var(size,align);1371 l = get_temp_local_var(size, align, &r2);
1377 sv.r = VT_LOCAL | VT_LVAL;1372 sv.r = VT_LOCAL | VT_LVAL;
1378 sv.c.i = l;1373 sv.c.i = l;
1379 store(p->r & VT_VALMASK, &sv);1374 store(p->r & VT_VALMASK, &sv);
@@ -1400,7 +1395,7 @@ ST_FUNC void save_reg_upstack(int r, int n) · 20 unmodified lines
1400 p->type.t &= ~VT_ARRAY; /* cannot combine VT_LVAL with VT_ARRAY */1395 p->type.t &= ~VT_ARRAY; /* cannot combine VT_LVAL with VT_ARRAY */
1401 }1396 }
1402 p->sym = NULL;1397 p->sym = NULL;
1403 p->r2 = VT_CONST;1398 p->r2 = r2;
1404 p->c.i = l;1399 p->c.i = l;
1405 }1400 }
1406 }1401 }
@@ -1471,54 +1466,46 @@ ST_FUNC int get_reg(int rc) · 64 unmodified lines
1471 return -1;1466 return -1;
1472}1467}
1473 1468
1474/* find a free temporary local variable (return the offset on stack) match the size and align. If none, add new temporary stack variable*/1469/* find a free temporary local variable (return the offset on stack) match
1475static int get_temp_local_var(int size,int align){1470 size and align. If none, add new temporary stack variable */
1476 int i;1471static int get_temp_local_var(int size,int align, int *r2)
1477 struct temp_local_variable *temp_var;1472{
1478 int found_var;1473 int i;
1479 SValue *p;1474 struct temp_local_variable *temp_var;
1480 int r;1475 SValue *p;
1481 char free;1476 int r;
1482 char found;1477 unsigned used = 0;
1483 found=0;1478
1484 for(i=0;i<nb_temp_local_vars;i++){1479 /* mark locations that are still in use */
1485 temp_var=&arr_temp_local_vars[i];1480 for (p = vstack; p <= vtop; p++) {
1486 if(temp_var->size<size||align!=temp_var->align){1481 r = p->r & VT_VALMASK;
1487 continue;1482 if (r == VT_LOCAL || r == VT_LLOCAL) {
1488 }1483 r = p->r2 - (VT_CONST + 1);
1489 /*check if temp_var is free*/1484 if (r >= 0 && r < MAX_TEMP_LOCAL_VARIABLE_NUMBER)
1490 free=1;1485 used |= 1<<r;
1491 for(p=vstack;p<=vtop;p++) {
1492 r=p->r&VT_VALMASK;
1493 if(r==VT_LOCAL||r==VT_LLOCAL){
1494 if(p->c.i==temp_var->location){
1495 free=0;
1496 break;
1497 }
1498 }
1499 }
1500 if(free){
1501 found_var=temp_var->location;
1502 found=1;
1503 break;
1504 }
1505 }1486 }
1506 if(!found){1487 }
1507 loc = (loc - size) & -align;1488 for (i=0;i<nb_temp_local_vars;i++) {
1508 if(nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER){1489 temp_var=&arr_temp_local_vars[i];
1509 temp_var=&arr_temp_local_vars[i];1490 if(!(used & 1<<i)
1510 temp_var->location=loc;1491 && temp_var->size>=size
1511 temp_var->size=size;1492 && temp_var->align>=align) {
1512 temp_var->align=align;1493ret_tmp:
1513 nb_temp_local_vars++;1494 *r2 = (VT_CONST + 1) + i;
1514 }1495 return temp_var->location;
1515 found_var=loc;
1516 }1496 }
1517 return found_var;1497 }
1518}1498 loc = (loc - size) & -align;
1519 1499 if (nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER) {
1520static void clear_temp_local_var_list(){1500 temp_var=&arr_temp_local_vars[i];
1521 nb_temp_local_vars=0;1501 temp_var->location=loc;
1502 temp_var->size=size;
1503 temp_var->align=align;
1504 nb_temp_local_vars++;
1505 goto ret_tmp;
1506 }
1507 *r2 = VT_CONST;
1508 return loc;
1522}1509}
1523 1510
1524/* move register 's' (of type 't') to 'r', and flush previous value of r to memory1511/* move register 's' (of type 't') to 'r', and flush previous value of r to memory
@@ -6056,6 +6043,7 @@ special_math_val: · 4531 unmodified lines
6056 SValue ret;6043 SValue ret;
6057 Sym *sa;6044 Sym *sa;
6058 int nb_args, ret_nregs, ret_align, regsize, variadic;6045 int nb_args, ret_nregs, ret_align, regsize, variadic;
6046 TokenString *p, *p2;
6059 6047
6060 /* function call */6048 /* function call */
6061 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {6049 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -6120,10 +6108,18 @@ special_math_val: · 58 unmodified lines
6120 ret.c.i = 0;6108 ret.c.i = 0;
6121 PUT_R_RET(&ret, ret.type.t);6109 PUT_R_RET(&ret, ret.type.t);
6122 }6110 }
6111
6112 p = NULL;
6123 if (tok != ')') {6113 if (tok != ')') {
6114 r = tcc_state->reverse_funcargs;
6124 for(;;) {6115 for(;;) {
6125 expr_eq();6116 if (r) {
6126 gfunc_param_typed(s, sa);6117 skip_or_save_block(&p2);
6118 p2->prev = p, p = p2;
6119 } else {
6120 expr_eq();
6121 gfunc_param_typed(s, sa);
6122 }
6127 nb_args++;6123 nb_args++;
6128 if (sa)6124 if (sa)
6129 sa = sa->next;6125 sa = sa->next;
@@ -6134,7 +6130,23 @@ special_math_val: · 4 unmodified lines
6134 }6130 }
6135 if (sa)6131 if (sa)
6136 tcc_error("too few arguments to function");6132 tcc_error("too few arguments to function");
6137 skip(')');6133
6134 if (p) { /* with reverse_funcargs */
6135 for (n = 0; p; p = p2, ++n) {
6136 p2 = p, sa = s;
6137 do {
6138 sa = sa->next, p2 = p2->prev;
6139 } while (p2 && sa);
6140 p2 = p->prev;
6141 begin_macro(p, 1), next();
6142 expr_eq();
6143 gfunc_param_typed(s, sa);
6144 end_macro();
6145 }
6146 vrev(n);
6147 }
6148
6149 next();
6138 gfunc_call(nb_args);6150 gfunc_call(nb_args);
6139 6151
6140 if (ret_nregs < 0) {6152 if (ret_nregs < 0) {
@@ -8335,12 +8347,12 @@ static void gen_function(Sym *sym) · 2194 unmodified lines
8335 /* push a dummy symbol to enable local sym storage */8347 /* push a dummy symbol to enable local sym storage */
8336 sym_push2(&local_stack, SYM_FIELD, 0, 0);8348 sym_push2(&local_stack, SYM_FIELD, 0, 0);
8337 local_scope = 1; /* for function parameters */8349 local_scope = 1; /* for function parameters */
8350 nb_temp_local_vars = 0;
8338 gfunc_prolog(sym);8351 gfunc_prolog(sym);
8339 tcc_debug_prolog_epilog(tcc_state, 0);8352 tcc_debug_prolog_epilog(tcc_state, 0);
8340 8353
8341 local_scope = 0;8354 local_scope = 0;
8342 rsym = 0;8355 rsym = 0;
8343 clear_temp_local_var_list();
8344 func_vla_arg(sym);8356 func_vla_arg(sym);
8345 block(0);8357 block(0);
8346 gsym(rsym);8358 gsym(rsym);
tests/tests2/60_errors_and_warnings.c+10−0
@@ -505,5 +505,15 @@ int main() · 504 unmodified lines
505 case 5:505 case 5:
506 }506 }
507}507}
508#elif defined test_normal_funcargs || defined test_reverse_funcargs
509
510#ifdef test_reverse_funcargs
511# pragma comment(option, "-freverse-funcargs")
512#endif
513int printf(const char*, ...);
514int main()
515{
516 printf(" %d %d %d\n", printf("1"), printf("22"), printf("333"));
517}
508 518
509#endif519#endif
tests/tests2/60_errors_and_warnings.expect+7−1
@@ -243,4 +243,10 @@ arg[1] = "Y" · 242 unmodified lines
243 243
244[test_duplicate_case]244[test_duplicate_case]
24560_errors_and_warnings.c:499: warning: empty case range24560_errors_and_warnings.c:499: warning: empty case range
24660_errors_and_warnings.c:507: error: duplicate case value24660_errors_and_warnings.c:503: error: duplicate case value
247
248[test_normal_funcargs]
249122333 1 2 3
250
251[test_reverse_funcargs]
252333221 1 2 3

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t