Collect cases first, then emit lookup code. Elliminates jumps to implement pass-through and jumps to link cases.
Unified · Split
| @@ -72,6 +72,13 @@ ST_DATA const char *funcname; · 71 unmodified lines | ||
| 72 | 72 | |
| 73 | 73 | ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; |
| 74 | 74 | |
| 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 | + | |
| 75 | 82 | /* ------------------------------------------------------------------------- */ |
| 76 | 83 | static void gen_cast(CType *type); |
| 77 | 84 | static inline CType *pointed_type(CType *type); |
| @@ -80,7 +87,7 @@ static int parse_btype(CType *type, AttributeDef *ad); · 2 unmodified lines | ||
| 80 | 87 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
| 81 | 88 | static void parse_expr_type(CType *type); |
| 82 | 89 | 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); | |
| 84 | 91 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); |
| 85 | 92 | static int decl0(int l, int is_for_loop_init); |
| 86 | 93 | static void expr_eq(void); |
| @@ -3859,7 +3866,7 @@ ST_FUNC void unary(void) · 3772 unmodified lines | ||
| 3859 | 3866 | save_regs(0); |
| 3860 | 3867 | /* statement expression : we do not accept break/continue |
| 3861 | 3868 | inside as GCC does */ |
| 3862 | − block(NULL, NULL, NULL, NULL, 0, 1); | |
| 3869 | + block(NULL, NULL, 1); | |
| 3863 | 3870 | skip(')'); |
| 3864 | 3871 | } else { |
| 3865 | 3872 | gexpr(); |
| @@ -4876,8 +4883,10 @@ static void label_or_decl(int l) · 1010 unmodified lines | ||
| 4876 | 4883 | decl(l); |
| 4877 | 4884 | } |
| 4878 | 4885 | |
| 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) | |
| 4881 | 4890 | { |
| 4882 | 4891 | int a, b, c, d; |
| 4883 | 4892 | Sym *s; |
| @@ -4903,13 +4912,13 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 19 unmodified lines | ||
| 4903 | 4912 | gexpr(); |
| 4904 | 4913 | skip(')'); |
| 4905 | 4914 | a = gvtst(1, 0); |
| 4906 | − block(bsym, csym, case_sym, def_sym, case_reg, 0); | |
| 4915 | + block(bsym, csym, 0); | |
| 4907 | 4916 | c = tok; |
| 4908 | 4917 | if (c == TOK_ELSE) { |
| 4909 | 4918 | next(); |
| 4910 | 4919 | d = gjmp(0); |
| 4911 | 4920 | gsym(a); |
| 4912 | − block(bsym, csym, case_sym, def_sym, case_reg, 0); | |
| 4921 | + block(bsym, csym, 0); | |
| 4913 | 4922 | gsym(d); /* patch else jmp */ |
| 4914 | 4923 | } else |
| 4915 | 4924 | gsym(a); |
| @@ -4923,7 +4932,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines | ||
| 4923 | 4932 | a = gvtst(1, 0); |
| 4924 | 4933 | b = 0; |
| 4925 | 4934 | ++local_scope; |
| 4926 | − block(&a, &b, case_sym, def_sym, case_reg, 0); | |
| 4935 | + block(&a, &b, 0); | |
| 4927 | 4936 | --local_scope; |
| 4928 | 4937 | if(!nocode_wanted) |
| 4929 | 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 | 4969 | if (tok != '}') { |
| 4961 | 4970 | if (is_expr) |
| 4962 | 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 | 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 | 5124 | gsym(e); |
| 5116 | 5125 | } |
| 5117 | 5126 | skip(')'); |
| 5118 | − block(&a, &b, case_sym, def_sym, case_reg, 0); | |
| 5127 | + block(&a, &b, 0); | |
| 5119 | 5128 | if(!nocode_wanted) |
| 5120 | 5129 | gjmp_addr(c); |
| 5121 | 5130 | gsym(a); |
| @@ -5130,7 +5139,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 8 unmodified lines | ||
| 5130 | 5139 | b = 0; |
| 5131 | 5140 | d = ind; |
| 5132 | 5141 | vla_sp_restore(); |
| 5133 | − block(&a, &b, case_sym, def_sym, case_reg, 0); | |
| 5142 | + block(&a, &b, 0); | |
| 5134 | 5143 | skip(TOK_WHILE); |
| 5135 | 5144 | skip('('); |
| 5136 | 5145 | gsym(b); |
| @@ -5142,58 +5151,65 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 5 unmodified lines | ||
| 5142 | 5151 | skip(';'); |
| 5143 | 5152 | } else |
| 5144 | 5153 | if (tok == TOK_SWITCH) { |
| 5154 | + struct switch_t *saved, sw; | |
| 5145 | 5155 | next(); |
| 5146 | 5156 | skip('('); |
| 5147 | 5157 | gexpr(); |
| 5148 | 5158 | /* XXX: other types than integer */ |
| 5149 | − case_reg = gv(RC_INT); | |
| 5159 | + c = gv(RC_INT); | |
| 5150 | 5160 | vpop(); |
| 5151 | 5161 | skip(')'); |
| 5152 | 5162 | a = 0; |
| 5153 | 5163 | 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); | |
| 5161 | 5196 | /* break label */ |
| 5162 | 5197 | gsym(a); |
| 5163 | 5198 | } else |
| 5164 | 5199 | 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) | |
| 5167 | 5202 | expect("switch"); |
| 5168 | 5203 | next(); |
| 5169 | − v1 = expr_const(); | |
| 5170 | − v2 = v1; | |
| 5204 | + cr->v1 = cr->v2 = expr_const(); | |
| 5171 | 5205 | if (gnu_ext && tok == TOK_DOTS) { |
| 5172 | 5206 | next(); |
| 5173 | − v2 = expr_const(); | |
| 5174 | − if (v2 < v1) | |
| 5207 | + cr->v2 = expr_const(); | |
| 5208 | + if (cr->v2 < cr->v1) | |
| 5175 | 5209 | tcc_warning("empty case range"); |
| 5176 | 5210 | } |
| 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); | |
| 5197 | 5213 | skip(':'); |
| 5198 | 5214 | is_expr = 0; |
| 5199 | 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 | 5217 | if (tok == TOK_DEFAULT) { |
| 5202 | 5218 | next(); |
| 5203 | 5219 | skip(':'); |
| 5204 | − if (!def_sym) | |
| 5220 | + if (!cur_switch) | |
| 5205 | 5221 | expect("switch"); |
| 5206 | − if (*def_sym) | |
| 5222 | + if (cur_switch->def_sym) | |
| 5207 | 5223 | tcc_error("too many 'default'"); |
| 5208 | − *def_sym = ind; | |
| 5224 | + cur_switch->def_sym = ind; | |
| 5209 | 5225 | is_expr = 0; |
| 5210 | 5226 | goto block_after_label; |
| 5211 | 5227 | } else |
| @@ -5261,7 +5277,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 49 unmodified lines | ||
| 5261 | 5277 | } else { |
| 5262 | 5278 | if (is_expr) |
| 5263 | 5279 | vpop(); |
| 5264 | − block(bsym, csym, case_sym, def_sym, case_reg, is_expr); | |
| 5280 | + block(bsym, csym, is_expr); | |
| 5265 | 5281 | } |
| 5266 | 5282 | } else { |
| 5267 | 5283 | /* expression case */ |
| @@ -6177,7 +6193,7 @@ static void gen_function(Sym *sym) · 909 unmodified lines | ||
| 6177 | 6193 | } |
| 6178 | 6194 | #endif |
| 6179 | 6195 | rsym = 0; |
| 6180 | − block(NULL, NULL, NULL, NULL, 0, 0); | |
| 6196 | + block(NULL, NULL, 0); | |
| 6181 | 6197 | gsym(rsym); |
| 6182 | 6198 | gfunc_epilog(); |
| 6183 | 6199 | cur_text_section->data_offset = ind; |