aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-09-26 20:31:24 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:47:12 +0100
commitca435dc2e36c685a225933283841ab3a827c3316 (patch)
tree880c2179942504895e7b21971fa68c36f064e57a
parent31c7ea0165882eaf09040ea7edfc37cc38f0a032 (diff)
downloadtinycc-ca435dc2e36c685a225933283841ab3a827c3316.tar.gz
tinycc-ca435dc2e36c685a225933283841ab3a827c3316.tar.bz2
opt: Make break and goto not fallthrough
As we can optimize dead code a bit already it's fitting to disable code emission after break and goto.
-rw-r--r--tccgen.c19
-rw-r--r--tests/tcctest.c51
2 files changed, 68 insertions, 2 deletions
diff --git a/tccgen.c b/tccgen.c
index 8b1bcb1..c9d43b4 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -5396,7 +5396,8 @@ static void block(int *bsym, int *csym, int is_expr)
nocode_wanted |= 2;
a = gvtst(1, 0);
block(bsym, csym, 0);
- nocode_wanted = saved_nocode_wanted;
+ if (cond != 1)
+ nocode_wanted = saved_nocode_wanted;
c = tok;
if (c == TOK_ELSE) {
next();
@@ -5406,10 +5407,12 @@ static void block(int *bsym, int *csym, int is_expr)
gsym(a);
block(bsym, csym, 0);
gsym(d); /* patch else jmp */
- nocode_wanted = saved_nocode_wanted;
+ if (cond != 0)
+ nocode_wanted = saved_nocode_wanted;
} else
gsym(a);
} else if (tok == TOK_WHILE) {
+ int saved_nocode_wanted;
nocode_wanted &= ~2;
next();
d = ind;
@@ -5420,7 +5423,9 @@ static void block(int *bsym, int *csym, int is_expr)
a = gvtst(1, 0);
b = 0;
++local_scope;
+ saved_nocode_wanted = nocode_wanted;
block(&a, &b, 0);
+ nocode_wanted = saved_nocode_wanted;
--local_scope;
if(!nocode_wanted)
gjmp_addr(d);
@@ -5556,6 +5561,7 @@ static void block(int *bsym, int *csym, int is_expr)
/* jump unless last stmt in top-level block */
if (tok != '}' || local_scope != 1)
rsym = gjmp(rsym);
+ nocode_wanted |= 2;
} else if (tok == TOK_BREAK) {
/* compute jump */
if (!bsym)
@@ -5563,6 +5569,7 @@ static void block(int *bsym, int *csym, int is_expr)
*bsym = gjmp(*bsym);
next();
skip(';');
+ nocode_wanted |= 2;
} else if (tok == TOK_CONTINUE) {
/* compute jump */
if (!csym)
@@ -5573,6 +5580,7 @@ static void block(int *bsym, int *csym, int is_expr)
skip(';');
} else if (tok == TOK_FOR) {
int e;
+ int saved_nocode_wanted;
nocode_wanted &= ~2;
next();
skip('(');
@@ -5607,7 +5615,9 @@ static void block(int *bsym, int *csym, int is_expr)
gsym(e);
}
skip(')');
+ saved_nocode_wanted = nocode_wanted;
block(&a, &b, 0);
+ nocode_wanted = saved_nocode_wanted;
if(!nocode_wanted)
gjmp_addr(c);
gsym(a);
@@ -5617,13 +5627,16 @@ static void block(int *bsym, int *csym, int is_expr)
} else
if (tok == TOK_DO) {
+ int saved_nocode_wanted;
nocode_wanted &= ~2;
next();
a = 0;
b = 0;
d = ind;
vla_sp_restore();
+ saved_nocode_wanted = nocode_wanted;
block(&a, &b, 0);
+ nocode_wanted = saved_nocode_wanted;
skip(TOK_WHILE);
skip('(');
gsym(b);
@@ -5637,6 +5650,7 @@ static void block(int *bsym, int *csym, int is_expr)
} else
if (tok == TOK_SWITCH) {
struct switch_t *saved, sw;
+ int saved_nocode_wanted = nocode_wanted;
next();
skip('(');
gexpr();
@@ -5650,6 +5664,7 @@ static void block(int *bsym, int *csym, int is_expr)
saved = cur_switch;
cur_switch = &sw;
block(&a, csym, 0);
+ nocode_wanted = saved_nocode_wanted;
a = gjmp(a); /* add implicit break */
/* case lookup */
gsym(b);
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 8031af4..a0ddc84 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -1184,6 +1184,57 @@ void optimize_out(void)
printf("oo:%d\n", defined_function());
else
printf("oo:%d\n", undefined_function());
+ while (1) {
+ printf("oow:%d\n", defined_function());
+ break;
+ printf("oow:%d\n", undefined_function());
+ }
+ j = 1;
+ /* Following is a switch without {} block intentionally. */
+ switch (j)
+ case 1: break;
+ printf ("oos:%d\n", defined_function());
+ /* The following break shouldn't lead to disabled code after
+ the while. */
+ while (1)
+ break;
+ printf ("ool1:%d\n", defined_function());
+ /* Same for the other types of loops. */
+ do
+ break;
+ while (1);
+ printf ("ool2:%d\n", defined_function());
+ for (;;)
+ break;
+ printf ("ool3:%d\n", defined_function());
+ /* Normal {} blocks without controlling statements
+ shouldn't reactivate code emission */
+ while (1) {
+ {
+ break;
+ }
+ printf ("ool4:%d\n", undefined_function());
+ }
+ j = 1;
+ while (j) {
+ if (j == 0)
+ break; /* this break shouldn't disable code outside the if. */
+ printf("ool5:%d\n", defined_function());
+ j--;
+ }
+
+ j = 1;
+ while (j) {
+ if (1)
+ j--;
+ else
+ breakhere: break;
+ printf("ool6:%d\n", defined_function());
+ goto breakhere;
+ }
+ if (1)
+ return;
+ printf ("oor:%d\n", undefined_function());
}
int defined_function(void)