History

opt: Start optimizing dead code a bit

If a condition is always zero/non-zero we can omit the then or else code. This is complicated a bit by having to deal with labels that might make such code reachable without us yet knowing during parsing.

Michael Matz committed 10 years ago

Commit 31c7ea01 parent b303a004 files · +182 −2Browse files

Unified · Split

4 files
  1. tccgen.c +15 −2
  2. tests/tcctest.c +27 −0
  3. tests/tests2/87_dead_code.c +122 −0
  4. tests/tests2/87_dead_code.expect +18 −0
tccgen.c+15−2
@@ -5367,7 +5367,7 @@ static int gcase(struct case_t **base, int len, int case_reg, int *bsym) · 5366 unmodified lines
5367 5367
5368static void block(int *bsym, int *csym, int is_expr)5368static void block(int *bsym, int *csym, int is_expr)
5369{5369{
5370 int a, b, c, d;5370 int a, b, c, d, cond;
5371 Sym *s;5371 Sym *s;
5372 5372
5373 /* generate line number info */5373 /* generate line number info */
@@ -5386,22 +5386,31 @@ static void block(int *bsym, int *csym, int is_expr) · 12 unmodified lines
5386 5386
5387 if (tok == TOK_IF) {5387 if (tok == TOK_IF) {
5388 /* if test */5388 /* if test */
5389 int saved_nocode_wanted = nocode_wanted;
5389 next();5390 next();
5390 skip('(');5391 skip('(');
5391 gexpr();5392 gexpr();
5392 skip(')');5393 skip(')');
5393 a = gvtst(1, 0);5394 cond = condition_3way();
5395 if (cond == 0)
5396 nocode_wanted |= 2;
5397 a = gvtst(1, 0);
5394 block(bsym, csym, 0);5398 block(bsym, csym, 0);
5399 nocode_wanted = saved_nocode_wanted;
5395 c = tok;5400 c = tok;
5396 if (c == TOK_ELSE) {5401 if (c == TOK_ELSE) {
5397 next();5402 next();
5403 if (cond == 1)
5404 nocode_wanted |= 2;
5398 d = gjmp(0);5405 d = gjmp(0);
5399 gsym(a);5406 gsym(a);
5400 block(bsym, csym, 0);5407 block(bsym, csym, 0);
5401 gsym(d); /* patch else jmp */5408 gsym(d); /* patch else jmp */
5409 nocode_wanted = saved_nocode_wanted;
5402 } else5410 } else
5403 gsym(a);5411 gsym(a);
5404 } else if (tok == TOK_WHILE) {5412 } else if (tok == TOK_WHILE) {
5413 nocode_wanted &= ~2;
5405 next();5414 next();
5406 d = ind;5415 d = ind;
5407 vla_sp_restore();5416 vla_sp_restore();
@@ -5564,6 +5573,7 @@ static void block(int *bsym, int *csym, int is_expr) · 156 unmodified lines
5564 skip(';');5573 skip(';');
5565 } else if (tok == TOK_FOR) {5574 } else if (tok == TOK_FOR) {
5566 int e;5575 int e;
5576 nocode_wanted &= ~2;
5567 next();5577 next();
5568 skip('(');5578 skip('(');
5569 s = local_stack;5579 s = local_stack;
@@ -5607,6 +5617,7 @@ static void block(int *bsym, int *csym, int is_expr) · 37 unmodified lines
5607 5617
5608 } else 5618 } else
5609 if (tok == TOK_DO) {5619 if (tok == TOK_DO) {
5620 nocode_wanted &= ~2;
5610 next();5621 next();
5611 a = 0;5622 a = 0;
5612 b = 0;5623 b = 0;
@@ -5658,6 +5669,7 @@ static void block(int *bsym, int *csym, int is_expr) · 45 unmodified lines
5658 struct case_t *cr = tcc_malloc(sizeof(struct case_t));5669 struct case_t *cr = tcc_malloc(sizeof(struct case_t));
5659 if (!cur_switch)5670 if (!cur_switch)
5660 expect("switch");5671 expect("switch");
5672 nocode_wanted &= ~2;
5661 next();5673 next();
5662 cr->v1 = cr->v2 = expr_const();5674 cr->v1 = cr->v2 = expr_const();
5663 if (gnu_ext && tok == TOK_DOTS) {5675 if (gnu_ext && tok == TOK_DOTS) {
@@ -5735,6 +5747,7 @@ static void block(int *bsym, int *csym, int is_expr) · 71 unmodified lines
5735 vla_sp_restore();5747 vla_sp_restore();
5736 /* we accept this, but it is a mistake */5748 /* we accept this, but it is a mistake */
5737 block_after_label:5749 block_after_label:
5750 nocode_wanted &= ~2;
5738 if (tok == '}') {5751 if (tok == '}') {
5739 tcc_warning("deprecated use of label at end of compound statement");5752 tcc_warning("deprecated use of label at end of compound statement");
5740 } else {5753 } else {
tests/tcctest.c+27−0
@@ -88,6 +88,7 @@ void struct_test(); · 87 unmodified lines
88void array_test();88void array_test();
89void expr_ptr_test();89void expr_ptr_test();
90void bool_test();90void bool_test();
91void optimize_out();
91void expr2_test();92void expr2_test();
92void constant_expr_test();93void constant_expr_test();
93void expr_cmp_test();94void expr_cmp_test();
@@ -695,6 +696,7 @@ int main(int argc, char **argv) · 601 unmodified lines
695 array_test();696 array_test();
696 expr_ptr_test();697 expr_ptr_test();
697 bool_test();698 bool_test();
699 optimize_out();
698 expr2_test();700 expr2_test();
699 constant_expr_test();701 constant_expr_test();
700 expr_cmp_test();702 expr_cmp_test();
@@ -1165,6 +1167,31 @@ void bool_test() · 464 unmodified lines
1165 printf ("bits = 0x%x\n", calc_vm_flags (0x1));1167 printf ("bits = 0x%x\n", calc_vm_flags (0x1));
1166}1168}
1167 1169
1170extern int undefined_function(void);
1171extern int defined_function(void);
1172
1173void optimize_out(void)
1174{
1175 int i = 0 ? undefined_function() : defined_function();
1176 printf ("oo:%d\n", i);
1177 int j = 1 ? defined_function() : undefined_function();
1178 printf ("oo:%d\n", j);
1179 if (0)
1180 printf("oo:%d\n", undefined_function());
1181 else
1182 printf("oo:%d\n", defined_function());
1183 if (1)
1184 printf("oo:%d\n", defined_function());
1185 else
1186 printf("oo:%d\n", undefined_function());
1187}
1188
1189int defined_function(void)
1190{
1191 static int i = 40;
1192 return i++;
1193}
1194
1168/* GCC accepts that */1195/* GCC accepts that */
1169static int tab_reinit[];1196static int tab_reinit[];
1170static int tab_reinit[10];1197static int tab_reinit[10];
tests/tests2/87_dead_code.c+122−0
@@ -0,0 +1,122 @@
1/* This checks various ways of dead code inside if statements
2 where there are non-obvious ways of how the code is actually
3 not dead due to reachable by labels. */
4extern int printf (const char *, ...);
5static void kb_wait_1(void)
6{
7 unsigned long timeout = 2;
8 do {
9 /* Here the else arm is a statement expression that's supposed
10 to be suppressed. The label inside the while would unsuppress
11 code generation again if not handled correctly. And that
12 would wreak havok to the cond-expression because there's no
13 jump-around emitted, the whole statement expression really
14 needs to not generate code (perhaps except useless forward jumps). */
15 (1 ?
16 printf("timeout=%ld\n", timeout) :
17 ({
18 int i = 1;
19 while (1)
20 while (i--)
21 some_label:
22 printf("error\n");
23 goto some_label;
24 })
25 );
26 timeout--;
27 } while (timeout);
28}
29int main (void)
30{
31 int i = 1;
32 kb_wait_1();
33
34 /* Simple test of dead code at first sight which isn't actually dead. */
35 if (0) {
36yeah:
37 printf ("yeah\n");
38 } else {
39 printf ("boo\n");
40 }
41 if (i--)
42 goto yeah;
43
44 /* Some more non-obvious uses where the problems are loops, so that even
45 the first loop statements aren't actually dead. */
46 i = 1;
47 if (0) {
48 while (i--) {
49 printf ("once\n");
50enterloop:
51 printf ("twice\n");
52 }
53 }
54 if (i >= 0)
55 goto enterloop;
56
57 /* The same with statement expressions. One might be tempted to
58 handle them specially by counting if inside statement exprs and
59 not unsuppressing code at loops at all then.
60 See kb_wait_1 for the other side of the medal where that wouldn't work. */
61 i = ({
62 int j = 1;
63 if (0) {
64 while (j--) {
65 printf ("SEonce\n");
66 enterexprloop:
67 printf ("SEtwice\n");
68 }
69 }
70 if (j >= 0)
71 goto enterexprloop;
72 j; });
73
74 /* The other two loop forms: */
75 i = 1;
76 if (0) {
77 for (i = 1; i--;) {
78 printf ("once2\n");
79enterloop2:
80 printf ("twice2\n");
81 }
82 }
83 if (i > 0)
84 goto enterloop2;
85
86 i = 1;
87 if (0) {
88 do {
89 printf ("once3\n");
90enterloop3:
91 printf ("twice3\n");
92 } while (i--);
93 }
94 if (i > 0)
95 goto enterloop3;
96
97 /* And check that case and default labels have the same effect
98 of disabling code suppression. */
99 i = 41;
100 switch (i) {
101 if (0) {
102 printf ("error\n");
103 case 42:
104 printf ("error2\n");
105 case 41:
106 printf ("caseok\n");
107 }
108 }
109
110 i = 41;
111 switch (i) {
112 if (0) {
113 printf ("error3\n");
114 default:
115 printf ("caseok2\n");
116 break;
117 case 42:
118 printf ("error4\n");
119 }
120 }
121 return 0;
122}
tests/tests2/87_dead_code.expect+18−0
@@ -0,0 +1,18 @@
1timeout=2
2timeout=1
3boo
4yeah
5twice
6once
7twice
8SEtwice
9SEonce
10SEtwice
11twice2
12once2
13twice2
14twice3
15once3
16twice3
17caseok
18caseok2