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
72 72
73ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;73ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
74 74
75ST_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
75/* ------------------------------------------------------------------------- */82/* ------------------------------------------------------------------------- */
76static void gen_cast(CType *type);83static void gen_cast(CType *type);
77static inline CType *pointed_type(CType *type);84static inline CType *pointed_type(CType *type);
@@ -80,7 +87,7 @@ static int parse_btype(CType *type, AttributeDef *ad); · 2 unmodified lines
80static void type_decl(CType *type, AttributeDef *ad, int *v, int td);87static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
81static void parse_expr_type(CType *type);88static void parse_expr_type(CType *type);
82static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);89static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
83static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg, int is_expr);90static void block(int *bsym, int *csym, int is_expr);
84static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);91static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
85static int decl0(int l, int is_for_loop_init);92static int decl0(int l, int is_for_loop_init);
86static void expr_eq(void);93static void expr_eq(void);
@@ -3859,7 +3866,7 @@ ST_FUNC void unary(void) · 3772 unmodified lines
3859 save_regs(0);3866 save_regs(0);
3860 /* statement expression : we do not accept break/continue3867 /* statement expression : we do not accept break/continue
3861 inside as GCC does */3868 inside as GCC does */
3862 block(NULL, NULL, NULL, NULL, 0, 1);3869 block(NULL, NULL, 1);
3863 skip(')');3870 skip(')');
3864 } else {3871 } else {
3865 gexpr();3872 gexpr();
@@ -4876,8 +4883,10 @@ static void label_or_decl(int l) · 1010 unmodified lines
4876 decl(l);4883 decl(l);
4877}4884}
4878 4885
4879static void block(int *bsym, int *csym, int *case_sym, int *def_sym, 4886static int case_cmp(const void *a, const void *b)
4880 int case_reg, int is_expr)4887{ return (*(struct case_t**) a)->v1 - (*(struct case_t**) b)->v1; }
4888
4889static void block(int *bsym, int *csym, int is_expr)
4881{4890{
4882 int a, b, c, d;4891 int a, b, c, d;
4883 Sym *s;4892 Sym *s;
@@ -4903,13 +4912,13 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 19 unmodified lines
4903 gexpr();4912 gexpr();
4904 skip(')');4913 skip(')');
4905 a = gvtst(1, 0);4914 a = gvtst(1, 0);
4906 block(bsym, csym, case_sym, def_sym, case_reg, 0);4915 block(bsym, csym, 0);
4907 c = tok;4916 c = tok;
4908 if (c == TOK_ELSE) {4917 if (c == TOK_ELSE) {
4909 next();4918 next();
4910 d = gjmp(0);4919 d = gjmp(0);
4911 gsym(a);4920 gsym(a);
4912 block(bsym, csym, case_sym, def_sym, case_reg, 0);4921 block(bsym, csym, 0);
4913 gsym(d); /* patch else jmp */4922 gsym(d); /* patch else jmp */
4914 } else4923 } else
4915 gsym(a);4924 gsym(a);
@@ -4923,7 +4932,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
4923 a = gvtst(1, 0);4932 a = gvtst(1, 0);
4924 b = 0;4933 b = 0;
4925 ++local_scope;4934 ++local_scope;
4926 block(&a, &b, case_sym, def_sym, case_reg, 0);4935 block(&a, &b, 0);
4927 --local_scope;4936 --local_scope;
4928 if(!nocode_wanted)4937 if(!nocode_wanted)
4929 gjmp_addr(d);4938 gjmp_addr(d);
@@ -4960,7 +4969,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 30 unmodified lines
4960 if (tok != '}') {4969 if (tok != '}') {
4961 if (is_expr)4970 if (is_expr)
4962 vpop();4971 vpop();
4963 block(bsym, csym, case_sym, def_sym, case_reg, is_expr);4972 block(bsym, csym, is_expr);
4964 }4973 }
4965 }4974 }
4966 /* pop locally defined labels */4975 /* pop locally defined labels */
@@ -5115,7 +5124,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 148 unmodified lines
5115 gsym(e);5124 gsym(e);
5116 }5125 }
5117 skip(')');5126 skip(')');
5118 block(&a, &b, case_sym, def_sym, case_reg, 0);5127 block(&a, &b, 0);
5119 if(!nocode_wanted)5128 if(!nocode_wanted)
5120 gjmp_addr(c);5129 gjmp_addr(c);
5121 gsym(a);5130 gsym(a);
@@ -5130,7 +5139,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 8 unmodified lines
5130 b = 0;5139 b = 0;
5131 d = ind;5140 d = ind;
5132 vla_sp_restore();5141 vla_sp_restore();
5133 block(&a, &b, case_sym, def_sym, case_reg, 0);5142 block(&a, &b, 0);
5134 skip(TOK_WHILE);5143 skip(TOK_WHILE);
5135 skip('(');5144 skip('(');
5136 gsym(b);5145 gsym(b);
@@ -5142,58 +5151,65 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 5 unmodified lines
5142 skip(';');5151 skip(';');
5143 } else5152 } else
5144 if (tok == TOK_SWITCH) {5153 if (tok == TOK_SWITCH) {
5154 struct switch_t *saved, sw;
5145 next();5155 next();
5146 skip('(');5156 skip('(');
5147 gexpr();5157 gexpr();
5148 /* XXX: other types than integer */5158 /* XXX: other types than integer */
5149 case_reg = gv(RC_INT);5159 c = gv(RC_INT);
5150 vpop();5160 vpop();
5151 skip(')');5161 skip(')');
5152 a = 0;5162 a = 0;
5153 b = gjmp(0); /* jump to first case */5163 b = gjmp(0); /* jump to first case */
5154 c = 0;5164 sw.p = NULL; sw.n = 0; sw.def_sym = 0;
5155 block(&a, csym, &b, &c, case_reg, 0);5165 saved = cur_switch;
5156 /* if no default, jmp after switch */5166 cur_switch = &sw; block(&a, csym, 0);
5157 if (c == 0)5167 cur_switch = saved;
5158 c = ind;5168 a = gjmp(a); /* add implicit break */
5159 /* default label */5169 gsym(b);
5160 gsym_addr(b, c);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);
5161 /* break label */5196 /* break label */
5162 gsym(a);5197 gsym(a);
5163 } else5198 } else
5164 if (tok == TOK_CASE) {5199 if (tok == TOK_CASE) {
5165 int v1, v2;5200 struct case_t *cr = tcc_malloc(sizeof(struct case_t));
5166 if (!case_sym)5201 if (!cur_switch)
5167 expect("switch");5202 expect("switch");
5168 next();5203 next();
5169 v1 = expr_const();5204 cr->v1 = cr->v2 = expr_const();
5170 v2 = v1;
5171 if (gnu_ext && tok == TOK_DOTS) {5205 if (gnu_ext && tok == TOK_DOTS) {
5172 next();5206 next();
5173 v2 = expr_const();5207 cr->v2 = expr_const();
5174 if (v2 < v1)5208 if (cr->v2 < cr->v1)
5175 tcc_warning("empty case range");5209 tcc_warning("empty case range");
5176 }5210 }
5177 /* since a case is like a label, we must skip it with a jmp */5211 cr->sym = ind;
5178 b = gjmp(0);5212 dynarray_add((void***) &cur_switch->p, &cur_switch->n, cr);
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);
5197 skip(':');5213 skip(':');
5198 is_expr = 0;5214 is_expr = 0;
5199 goto block_after_label;5215 goto block_after_label;
@@ -5201,11 +5217,11 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 1 unmodified line
5201 if (tok == TOK_DEFAULT) {5217 if (tok == TOK_DEFAULT) {
5202 next();5218 next();
5203 skip(':');5219 skip(':');
5204 if (!def_sym)5220 if (!cur_switch)
5205 expect("switch");5221 expect("switch");
5206 if (*def_sym)5222 if (cur_switch->def_sym)
5207 tcc_error("too many 'default'");5223 tcc_error("too many 'default'");
5208 *def_sym = ind;5224 cur_switch->def_sym = ind;
5209 is_expr = 0;5225 is_expr = 0;
5210 goto block_after_label;5226 goto block_after_label;
5211 } else5227 } else
@@ -5261,7 +5277,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 49 unmodified lines
5261 } else {5277 } else {
5262 if (is_expr)5278 if (is_expr)
5263 vpop();5279 vpop();
5264 block(bsym, csym, case_sym, def_sym, case_reg, is_expr);5280 block(bsym, csym, is_expr);
5265 }5281 }
5266 } else {5282 } else {
5267 /* expression case */5283 /* expression case */
@@ -6177,7 +6193,7 @@ static void gen_function(Sym *sym) · 909 unmodified lines
6177 }6193 }
6178#endif6194#endif
6179 rsym = 0;6195 rsym = 0;
6180 block(NULL, NULL, NULL, NULL, 0, 0);6196 block(NULL, NULL, 0);
6181 gsym(rsym);6197 gsym(rsym);
6182 gfunc_epilog();6198 gfunc_epilog();
6183 cur_text_section->data_offset = ind;6199 cur_text_section->data_offset = ind;