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
16731673 { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
16741674 { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
16751675 { offsetof(TCCState, test_coverage), 0, "test-coverage" },
1676+ { offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs" },
16761677 { 0, 0, NULL }
16771678 };
16781679
tcc.c+1−0
@@ -115,6 +115,7 @@ static const char help2[] = · 114 unmodified lines
115115 " leading-underscore decorate extern symbols\n"
116116 " ms-extensions allow anonymous struct in struct\n"
117117 " dollars-in-identifiers allow '$' in C symbols\n"
118+ " reverse-funcargs evaluate function arguments right to left\n"
118119 " test-coverage create code coverage code\n"
119120 "-m... target specific options:\n"
120121 " ms-bitfields use MSVC bitfield layout\n"
tcc.h+2−1
@@ -776,6 +776,7 @@ struct TCCState { · 775 unmodified lines
776776 unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
777777 unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */
778778 unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
779+ unsigned char reverse_funcargs; /* if true, evaluate last function arg first */
779780
780781 /* warning switches */
781782 unsigned char warn_none;
@@ -1490,9 +1491,9 @@ ST_FUNC void vpushi(int v); · 708 unmodified lines
14901491 ST_FUNC void vpushv(SValue *v);
14911492 ST_FUNC void vpushsym(CType *type, Sym *sym);
14921493 ST_FUNC void vswap(void);
1493−ST_FUNC void vrote(SValue *e, int n);
14941494 ST_FUNC void vrott(int n);
14951495 ST_FUNC void vrotb(int n);
1496+ST_FUNC void vrev(int n);
14961497 ST_FUNC void vpop(void);
14971498 #if PTR_SIZE == 4
14981499 ST_FUNC void lexpand(void);
tccgen.c+91−79
@@ -154,8 +154,7 @@ static void gen_inline_functions(TCCState *s); · 153 unmodified lines
154154 static void free_inline_functions(TCCState *s);
155155 static void skip_or_save_block(TokenString **str);
156156 static void gv_dup(void);
157−static int get_temp_local_var(int size,int align);
158−static void clear_temp_local_var_list();
157+static int get_temp_local_var(int size,int align,int *r2);
159158 static void cast_error(CType *st, CType *dt);
160159 static void end_switch(void);
161160
@@ -957,42 +956,38 @@ static void vdup(void) · 795 unmodified lines
957956 vpushv(vtop);
958957 }
959958
960−/* rotate n first stack elements to the bottom
961− I1 ... In -> I2 ... In I1 [top is right]
962−*/
959+/* rotate the stack element at position n-1 to the top */
963960 ST_FUNC void vrotb(int n)
964961 {
965− int i;
966962 SValue tmp;
967−
963+ if (--n < 1)
964+ return;
968965 vcheck_cmp();
969− tmp = vtop[-n + 1];
970− for(i=-n+1;i!=0;i++)
971− vtop[i] = vtop[i+1];
966+ tmp = vtop[-n];
967+ memmove(vtop - n, vtop - n + 1, sizeof *vtop * n);
972968 vtop[0] = tmp;
973969 }
974970
975−/* rotate the n elements before entry e towards the top
976− I1 ... In ... -> In I1 ... I(n-1) ... [top is right]
977− */
978−ST_FUNC void vrote(SValue *e, int n)
971+/* rotate the top stack element into position n-1 */
972+ST_FUNC void vrott(int n)
979973 {
980− int i;
981974 SValue tmp;
982−
975+ if (--n < 1)
976+ return;
983977 vcheck_cmp();
984− tmp = *e;
985− for(i = 0;i < n - 1; i++)
986− e[-i] = e[-i - 1];
987− e[-n + 1] = tmp;
978+ tmp = vtop[0];
979+ memmove(vtop - n + 1, vtop - n, sizeof *vtop * n);
980+ vtop[-n] = tmp;
988981 }
989982
990−/* rotate n first stack elements to the top
991− I1 ... In -> In I1 ... I(n-1) [top is right]
992− */
993−ST_FUNC void vrott(int n)
983+/* reverse order of the the first n stack elements */
984+ST_FUNC void vrev(int n)
994985 {
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;
996991 }
997992
998993 /* ------------------------------------------------------------------------- */
@@ -1354,14 +1349,14 @@ ST_FUNC void save_reg(int r) · 355 unmodified lines
13541349 if seen up to (vtop - n) stack entry */
13551350 ST_FUNC void save_reg_upstack(int r, int n)
13561351 {
1357− int l, size, align, bt;
1352+ int l, size, align, bt, r2;
13581353 SValue *p, *p1, sv;
13591354
13601355 if ((r &= VT_VALMASK) >= VT_CONST)
13611356 return;
13621357 if (nocode_wanted)
13631358 return;
1364− l = 0;
1359+ l = r2 = 0;
13651360 for(p = vstack, p1 = vtop - n; p <= p1; p++) {
13661361 if ((p->r & VT_VALMASK) == r || p->r2 == r) {
13671362 /* 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
13731368 bt = VT_PTR;
13741369 sv.type.t = bt;
13751370 size = type_size(&sv.type, &align);
1376− l = get_temp_local_var(size,align);
1371+ l = get_temp_local_var(size, align, &r2);
13771372 sv.r = VT_LOCAL | VT_LVAL;
13781373 sv.c.i = l;
13791374 store(p->r & VT_VALMASK, &sv);
@@ -1400,7 +1395,7 @@ ST_FUNC void save_reg_upstack(int r, int n) · 20 unmodified lines
14001395 p->type.t &= ~VT_ARRAY; /* cannot combine VT_LVAL with VT_ARRAY */
14011396 }
14021397 p->sym = NULL;
1403− p->r2 = VT_CONST;
1398+ p->r2 = r2;
14041399 p->c.i = l;
14051400 }
14061401 }
@@ -1471,54 +1466,46 @@ ST_FUNC int get_reg(int rc) · 64 unmodified lines
14711466 return -1;
14721467 }
14731468
1474−/* find a free temporary local variable (return the offset on stack) match the size and align. If none, add new temporary stack variable*/
1475−static int get_temp_local_var(int size,int align){
1476− int i;
1477− struct temp_local_variable *temp_var;
1478− int found_var;
1479− SValue *p;
1480− int r;
1481− char free;
1482− char found;
1483− found=0;
1484− for(i=0;i<nb_temp_local_vars;i++){
1485− temp_var=&arr_temp_local_vars[i];
1486− if(temp_var->size<size||align!=temp_var->align){
1487− continue;
1488− }
1489− /*check if temp_var is free*/
1490− free=1;
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− }
1469+/* find a free temporary local variable (return the offset on stack) match
1470+ size and align. If none, add new temporary stack variable */
1471+static int get_temp_local_var(int size,int align, int *r2)
1472+{
1473+ int i;
1474+ struct temp_local_variable *temp_var;
1475+ SValue *p;
1476+ int r;
1477+ unsigned used = 0;
1478+
1479+ /* mark locations that are still in use */
1480+ for (p = vstack; p <= vtop; p++) {
1481+ r = p->r & VT_VALMASK;
1482+ if (r == VT_LOCAL || r == VT_LLOCAL) {
1483+ r = p->r2 - (VT_CONST + 1);
1484+ if (r >= 0 && r < MAX_TEMP_LOCAL_VARIABLE_NUMBER)
1485+ used |= 1<<r;
15051486 }
1506− if(!found){
1507− loc = (loc - size) & -align;
1508− if(nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER){
1509− temp_var=&arr_temp_local_vars[i];
1510− temp_var->location=loc;
1511− temp_var->size=size;
1512− temp_var->align=align;
1513− nb_temp_local_vars++;
1514− }
1515− found_var=loc;
1487+ }
1488+ for (i=0;i<nb_temp_local_vars;i++) {
1489+ temp_var=&arr_temp_local_vars[i];
1490+ if(!(used & 1<<i)
1491+ && temp_var->size>=size
1492+ && temp_var->align>=align) {
1493+ret_tmp:
1494+ *r2 = (VT_CONST + 1) + i;
1495+ return temp_var->location;
15161496 }
1517− return found_var;
1518−}
1519−
1520−static void clear_temp_local_var_list(){
1521− nb_temp_local_vars=0;
1497+ }
1498+ loc = (loc - size) & -align;
1499+ if (nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER) {
1500+ temp_var=&arr_temp_local_vars[i];
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;
15221509 }
15231510
15241511 /* 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
60566043 SValue ret;
60576044 Sym *sa;
60586045 int nb_args, ret_nregs, ret_align, regsize, variadic;
6046+ TokenString *p, *p2;
60596047
60606048 /* function call */
60616049 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -6120,10 +6108,18 @@ special_math_val: · 58 unmodified lines
61206108 ret.c.i = 0;
61216109 PUT_R_RET(&ret, ret.type.t);
61226110 }
6111+
6112+ p = NULL;
61236113 if (tok != ')') {
6114+ r = tcc_state->reverse_funcargs;
61246115 for(;;) {
6125− expr_eq();
6126− gfunc_param_typed(s, sa);
6116+ if (r) {
6117+ skip_or_save_block(&p2);
6118+ p2->prev = p, p = p2;
6119+ } else {
6120+ expr_eq();
6121+ gfunc_param_typed(s, sa);
6122+ }
61276123 nb_args++;
61286124 if (sa)
61296125 sa = sa->next;
@@ -6134,7 +6130,23 @@ special_math_val: · 4 unmodified lines
61346130 }
61356131 if (sa)
61366132 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();
61386150 gfunc_call(nb_args);
61396151
61406152 if (ret_nregs < 0) {
@@ -8335,12 +8347,12 @@ static void gen_function(Sym *sym) · 2194 unmodified lines
83358347 /* push a dummy symbol to enable local sym storage */
83368348 sym_push2(&local_stack, SYM_FIELD, 0, 0);
83378349 local_scope = 1; /* for function parameters */
8350+ nb_temp_local_vars = 0;
83388351 gfunc_prolog(sym);
83398352 tcc_debug_prolog_epilog(tcc_state, 0);
83408353
83418354 local_scope = 0;
83428355 rsym = 0;
8343− clear_temp_local_var_list();
83448356 func_vla_arg(sym);
83458357 block(0);
83468358 gsym(rsym);
tests/tests2/60_errors_and_warnings.c+10−0
@@ -505,5 +505,15 @@ int main() · 504 unmodified lines
505505 case 5:
506506 }
507507 }
508+#elif defined test_normal_funcargs || defined test_reverse_funcargs
509+
510+#ifdef test_reverse_funcargs
511+# pragma comment(option, "-freverse-funcargs")
512+#endif
513+int printf(const char*, ...);
514+int main()
515+{
516+ printf(" %d %d %d\n", printf("1"), printf("22"), printf("333"));
517+}
508518
509519 #endif
tests/tests2/60_errors_and_warnings.expect+7−1
@@ -243,4 +243,10 @@ arg[1] = "Y" · 242 unmodified lines
243243
244244 [test_duplicate_case]
245245 60_errors_and_warnings.c:499: warning: empty case range
246−60_errors_and_warnings.c:507: error: duplicate case value
246+60_errors_and_warnings.c:503: error: duplicate case value
247+
248+[test_normal_funcargs]
249+122333 1 2 3
250+
251+[test_reverse_funcargs]
252+333221 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