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 | ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; | 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 | static void gen_cast(CType *type); | 83 | static void gen_cast(CType *type); |
| 77 | static inline CType *pointed_type(CType *type); | 84 | static inline CType *pointed_type(CType *type); |
| @@ -80,7 +87,7 @@ static int parse_btype(CType *type, AttributeDef *ad); · 2 unmodified lines | |||
| 80 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); | 87 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
| 81 | static void parse_expr_type(CType *type); | 88 | static void parse_expr_type(CType *type); |
| 82 | static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); | 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 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); | 91 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); |
| 85 | static int decl0(int l, int is_for_loop_init); | 92 | static int decl0(int l, int is_for_loop_init); |
| 86 | static void expr_eq(void); | 93 | static 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/continue | 3867 | /* 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 | ||
| 4879 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, | 4886 | static 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 | |||
| 4889 | static 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 | } else | 4923 | } 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 | } else | 5152 | } 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 | } else | 5198 | } 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 | } else | 5227 | } 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 | #endif | 6194 | #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; |