History

switch: collect case ranges first, then generate code

Collect cases first, then emit lookup code. Elliminates jumps to implement pass-through and jumps to link cases.

Pavlas, Zdenek committed 10 years ago

Commit fc0fc6a1 parent d5a1e321 file · +65 −49Browse files

Unified · Split

tccgen.c+65−49
@@ -72,6 +72,13 @@ ST_DATA const char *funcname; · 71 unmodified lines
7272
7373 ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
7474
75+ST_DATA struct switch_t {
76+ struct case_t {
77+ int v1, v2, sym;
78+ } **p; int n; /* list of case ranges */
79+ int def_sym; /* default symbol */
80+} *cur_switch; /* current switch */
81+
7582 /* ------------------------------------------------------------------------- */
7683 static void gen_cast(CType *type);
7784 static inline CType *pointed_type(CType *type);
@@ -80,7 +87,7 @@ static int parse_btype(CType *type, AttributeDef *ad); · 2 unmodified lines
8087 static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
8188 static void parse_expr_type(CType *type);
8289 static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
83−static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg, int is_expr);
90+static void block(int *bsym, int *csym, int is_expr);
8491 static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
8592 static int decl0(int l, int is_for_loop_init);
8693 static void expr_eq(void);
@@ -3859,7 +3866,7 @@ ST_FUNC void unary(void) · 3772 unmodified lines
38593866 save_regs(0);
38603867 /* statement expression : we do not accept break/continue
38613868 inside as GCC does */
3862− block(NULL, NULL, NULL, NULL, 0, 1);
3869+ block(NULL, NULL, 1);
38633870 skip(')');
38643871 } else {
38653872 gexpr();
@@ -4876,8 +4883,10 @@ static void label_or_decl(int l) · 1010 unmodified lines
48764883 decl(l);
48774884 }
48784885
4879−static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
4880− int case_reg, int is_expr)
4886+static int case_cmp(const void *a, const void *b)
4887+{ return (*(struct case_t**) a)->v1 - (*(struct case_t**) b)->v1; }
4888+
4889+static void block(int *bsym, int *csym, int is_expr)
48814890 {
48824891 int a, b, c, d;
48834892 Sym *s;
@@ -4903,13 +4912,13 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 19 unmodified lines
49034912 gexpr();
49044913 skip(')');
49054914 a = gvtst(1, 0);
4906− block(bsym, csym, case_sym, def_sym, case_reg, 0);
4915+ block(bsym, csym, 0);
49074916 c = tok;
49084917 if (c == TOK_ELSE) {
49094918 next();
49104919 d = gjmp(0);
49114920 gsym(a);
4912− block(bsym, csym, case_sym, def_sym, case_reg, 0);
4921+ block(bsym, csym, 0);
49134922 gsym(d); /* patch else jmp */
49144923 } else
49154924 gsym(a);
@@ -4923,7 +4932,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
49234932 a = gvtst(1, 0);
49244933 b = 0;
49254934 ++local_scope;
4926− block(&a, &b, case_sym, def_sym, case_reg, 0);
4935+ block(&a, &b, 0);
49274936 --local_scope;
49284937 if(!nocode_wanted)
49294938 gjmp_addr(d);
@@ -4960,7 +4969,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 30 unmodified lines
49604969 if (tok != '}') {
49614970 if (is_expr)
49624971 vpop();
4963− block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
4972+ block(bsym, csym, is_expr);
49644973 }
49654974 }
49664975 /* pop locally defined labels */
@@ -5115,7 +5124,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 148 unmodified lines
51155124 gsym(e);
51165125 }
51175126 skip(')');
5118− block(&a, &b, case_sym, def_sym, case_reg, 0);
5127+ block(&a, &b, 0);
51195128 if(!nocode_wanted)
51205129 gjmp_addr(c);
51215130 gsym(a);
@@ -5130,7 +5139,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 8 unmodified lines
51305139 b = 0;
51315140 d = ind;
51325141 vla_sp_restore();
5133− block(&a, &b, case_sym, def_sym, case_reg, 0);
5142+ block(&a, &b, 0);
51345143 skip(TOK_WHILE);
51355144 skip('(');
51365145 gsym(b);
@@ -5142,58 +5151,65 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 5 unmodified lines
51425151 skip(';');
51435152 } else
51445153 if (tok == TOK_SWITCH) {
5154+ struct switch_t *saved, sw;
51455155 next();
51465156 skip('(');
51475157 gexpr();
51485158 /* XXX: other types than integer */
5149− case_reg = gv(RC_INT);
5159+ c = gv(RC_INT);
51505160 vpop();
51515161 skip(')');
51525162 a = 0;
51535163 b = gjmp(0); /* jump to first case */
5154− c = 0;
5155− block(&a, csym, &b, &c, case_reg, 0);
5156− /* if no default, jmp after switch */
5157− if (c == 0)
5158− c = ind;
5159− /* default label */
5160− gsym_addr(b, c);
5164+ sw.p = NULL; sw.n = 0; sw.def_sym = 0;
5165+ saved = cur_switch;
5166+ cur_switch = &sw; block(&a, csym, 0);
5167+ cur_switch = saved;
5168+ a = gjmp(a); /* add implicit break */
5169+ gsym(b);
5170+
5171+ qsort(sw.p, sw.n, sizeof(void*), case_cmp);
5172+ for (b = 0; b < sw.n; b++) {
5173+ int v = sw.p[b]->v1;
5174+ if (b && v <= d)
5175+ tcc_error("duplicate case value");
5176+ d = sw.p[b]->v2;
5177+
5178+ vseti(c, 0);
5179+ vpushi(v);
5180+ if (v == d) {
5181+ gen_op(TOK_EQ);
5182+ gsym_addr(gtst(0, 0), sw.p[b]->sym);
5183+ } else {
5184+ int e;
5185+ gen_op(TOK_GE);
5186+ e = gtst(1, 0);
5187+ vseti(c, 0);
5188+ vpushi(d);
5189+ gen_op(TOK_LE);
5190+ gsym_addr(gtst(0, 0), sw.p[b]->sym);
5191+ gsym(e);
5192+ }
5193+ }
5194+ if (sw.def_sym)
5195+ gjmp_addr(sw.def_sym);
51615196 /* break label */
51625197 gsym(a);
51635198 } else
51645199 if (tok == TOK_CASE) {
5165− int v1, v2;
5166− if (!case_sym)
5200+ struct case_t *cr = tcc_malloc(sizeof(struct case_t));
5201+ if (!cur_switch)
51675202 expect("switch");
51685203 next();
5169− v1 = expr_const();
5170− v2 = v1;
5204+ cr->v1 = cr->v2 = expr_const();
51715205 if (gnu_ext && tok == TOK_DOTS) {
51725206 next();
5173− v2 = expr_const();
5174− if (v2 < v1)
5207+ cr->v2 = expr_const();
5208+ if (cr->v2 < cr->v1)
51755209 tcc_warning("empty case range");
51765210 }
5177− /* since a case is like a label, we must skip it with a jmp */
5178− b = gjmp(0);
5179− gsym(*case_sym);
5180− vseti(case_reg, 0);
5181− vdup();
5182− vpushi(v1);
5183− if (v1 == v2) {
5184− gen_op(TOK_EQ);
5185− *case_sym = gtst(1, 0);
5186− } else {
5187− gen_op(TOK_GE);
5188− *case_sym = gtst(1, 0);
5189− vseti(case_reg, 0);
5190− vpushi(v2);
5191− gen_op(TOK_LE);
5192− *case_sym = gtst(1, *case_sym);
5193− }
5194− case_reg = gv(RC_INT);
5195− vpop();
5196− gsym(b);
5211+ cr->sym = ind;
5212+ dynarray_add((void***) &cur_switch->p, &cur_switch->n, cr);
51975213 skip(':');
51985214 is_expr = 0;
51995215 goto block_after_label;
@@ -5201,11 +5217,11 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 1 unmodified line
52015217 if (tok == TOK_DEFAULT) {
52025218 next();
52035219 skip(':');
5204− if (!def_sym)
5220+ if (!cur_switch)
52055221 expect("switch");
5206− if (*def_sym)
5222+ if (cur_switch->def_sym)
52075223 tcc_error("too many 'default'");
5208− *def_sym = ind;
5224+ cur_switch->def_sym = ind;
52095225 is_expr = 0;
52105226 goto block_after_label;
52115227 } else
@@ -5261,7 +5277,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 49 unmodified lines
52615277 } else {
52625278 if (is_expr)
52635279 vpop();
5264− block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
5280+ block(bsym, csym, is_expr);
52655281 }
52665282 } else {
52675283 /* expression case */
@@ -6177,7 +6193,7 @@ static void gen_function(Sym *sym) · 909 unmodified lines
61776193 }
61786194 #endif
61796195 rsym = 0;
6180− block(NULL, NULL, NULL, NULL, 0, 0);
6196+ block(NULL, NULL, 0);
61816197 gsym(rsym);
61826198 gfunc_epilog();
61836199 cur_text_section->data_offset = ind;