| @@ -90,7 +90,7 @@ static CString initstr; · 89 unmodified lines |
| 90 | 90 | static struct switch_t { |
| 91 | 91 | struct case_t { |
| 92 | 92 | int64_t v1, v2; |
| 93 | | − int sym; |
| 93 | + int ind, line; |
| 94 | 94 | } **p; int n; /* list of case ranges */ |
| 95 | 95 | int def_sym; /* default symbol */ |
| 96 | 96 | int nocode_wanted; |
| @@ -2236,7 +2236,11 @@ static void gen_opl(int op) · 2139 unmodified lines |
| 2236 | 2236 | vtop[-1] = vtop[-2]; |
| 2237 | 2237 | vtop[-2] = tmp; |
| 2238 | 2238 | /* stack: L1 L2 H1 H2 */ |
| 2239 | | − save_regs(4); |
| 2239 | + if (!cur_switch || cur_switch->bsym) { |
| 2240 | + /* avoid differnt registers being saved in branches. |
| 2241 | + This is not needed when comparing switch cases */ |
| 2242 | + save_regs(4); |
| 2243 | + } |
| 2240 | 2244 | /* compare high */ |
| 2241 | 2245 | op1 = op; |
| 2242 | 2246 | /* when values are equal, we need to compare low words. since |
| @@ -2285,6 +2289,18 @@ static void gen_opl(int op) · 42 unmodified lines |
| 2285 | 2289 | } |
| 2286 | 2290 | #endif |
| 2287 | 2291 | |
| 2292 | +/* normalize values */ |
| 2293 | +static uint64_t value64(uint64_t l1, int t) |
| 2294 | +{ |
| 2295 | + if ((t & VT_BTYPE) == VT_LLONG |
| 2296 | + || (PTR_SIZE == 8 && (t & VT_BTYPE) == VT_PTR)) |
| 2297 | + return l1; |
| 2298 | + else if (t & VT_UNSIGNED) |
| 2299 | + return (uint32_t)l1; |
| 2300 | + else |
| 2301 | + return (uint32_t)l1 | -(l1 & 0x80000000); |
| 2302 | +} |
| 2303 | + |
| 2288 | 2304 | static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) |
| 2289 | 2305 | { |
| 2290 | 2306 | uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); |
| @@ -2306,18 +2322,11 @@ static void gen_opic(int op) · 15 unmodified lines |
| 2306 | 2322 | int t2 = v2->type.t & VT_BTYPE; |
| 2307 | 2323 | int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2308 | 2324 | int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2309 | | − uint64_t l1 = c1 ? v1->c.i : 0; |
| 2310 | | − uint64_t l2 = c2 ? v2->c.i : 0; |
| 2325 | + uint64_t l1 = c1 ? value64(v1->c.i, v1->type.t) : 0; |
| 2326 | + uint64_t l2 = c2 ? value64(v2->c.i, v2->type.t) : 0; |
| 2311 | 2327 | int shm = (t1 == VT_LLONG) ? 63 : 31; |
| 2312 | 2328 | int r; |
| 2313 | 2329 | |
| 2314 | | − if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) |
| 2315 | | − l1 = ((uint32_t)l1 | |
| 2316 | | − (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); |
| 2317 | | − if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR)) |
| 2318 | | − l2 = ((uint32_t)l2 | |
| 2319 | | − (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000))); |
| 2320 | | − |
| 2321 | 2330 | if (c1 && c2) { |
| 2322 | 2331 | switch(op) { |
| 2323 | 2332 | case '+': l1 += l2; break; |
| @@ -2367,10 +2376,7 @@ static void gen_opic(int op) · 43 unmodified lines |
| 2367 | 2376 | default: |
| 2368 | 2377 | goto general_case; |
| 2369 | 2378 | } |
| 2370 | | − if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) |
| 2371 | | − l1 = ((uint32_t)l1 | |
| 2372 | | − (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); |
| 2373 | | − v1->c.i = l1; |
| 2379 | + v1->c.i = value64(l1, v1->type.t); |
| 2374 | 2380 | v1->r |= v2->r & VT_NONCONST; |
| 2375 | 2381 | vtop--; |
| 2376 | 2382 | } else { |
| @@ -6701,79 +6707,74 @@ static void check_func_return(void) · 4324 unmodified lines |
| 6701 | 6707 | /* ------------------------------------------------------------------------- */ |
| 6702 | 6708 | /* switch/case */ |
| 6703 | 6709 | |
| 6704 | | −static int case_cmpi(const void *pa, const void *pb) |
| 6710 | +static int case_cmp(uint64_t a, uint64_t b) |
| 6705 | 6711 | { |
| 6706 | | − int64_t a = (*(struct case_t**) pa)->v1; |
| 6707 | | − int64_t b = (*(struct case_t**) pb)->v1; |
| 6708 | | − return a < b ? -1 : a > b; |
| 6712 | + if (cur_switch->sv.type.t & VT_UNSIGNED) |
| 6713 | + return a < b ? -1 : a > b; |
| 6714 | + else |
| 6715 | + return (int64_t)a < (int64_t)b ? -1 : (int64_t)a > (int64_t)b; |
| 6709 | 6716 | } |
| 6710 | 6717 | |
| 6711 | | −static int case_cmpu(const void *pa, const void *pb) |
| 6718 | +static int case_cmp_qs(const void *pa, const void *pb) |
| 6712 | 6719 | { |
| 6713 | | − uint64_t a = (uint64_t)(*(struct case_t**) pa)->v1; |
| 6714 | | − uint64_t b = (uint64_t)(*(struct case_t**) pb)->v1; |
| 6715 | | − return a < b ? -1 : a > b; |
| 6720 | + return case_cmp((*(struct case_t**)pa)->v1, (*(struct case_t**)pb)->v1); |
| 6716 | 6721 | } |
| 6717 | 6722 | |
| 6718 | | −static void gtst_addr(int t, int a) |
| 6723 | +static void case_sort(struct switch_t *sw) |
| 6719 | 6724 | { |
| 6720 | | − gsym_addr(gvtst(0, t), a); |
| 6725 | + struct case_t **p; |
| 6726 | + if (sw->n < 2) |
| 6727 | + return; |
| 6728 | + qsort(sw->p, sw->n, sizeof *sw->p, case_cmp_qs); |
| 6729 | + p = sw->p; |
| 6730 | + while (p < sw->p + sw->n - 1) { |
| 6731 | + if (case_cmp(p[0]->v2, p[1]->v1) >= 0) { |
| 6732 | + int l1 = p[0]->line, l2 = p[1]->line; |
| 6733 | + /* using special format "%i:..." to show specific line */ |
| 6734 | + tcc_error("%i:duplicate case value", l1 > l2 ? l1 : l2); |
| 6735 | + } else if (p[0]->v2 + 1 == p[1]->v1 && p[0]->ind == p[1]->ind) { |
| 6736 | + /* treat "case 1: case 2: case 3:" like "case 1 ... 3: */ |
| 6737 | + p[1]->v1 = p[0]->v1; |
| 6738 | + tcc_free(p[0]); |
| 6739 | + memmove(p, p + 1, (--sw->n - (p - sw->p)) * sizeof *p); |
| 6740 | + } else |
| 6741 | + ++p; |
| 6742 | + } |
| 6721 | 6743 | } |
| 6722 | 6744 | |
| 6723 | | −static void gcase(struct case_t **base, int len, int *bsym) |
| 6745 | +static int gcase(struct case_t **base, int len, int dsym) |
| 6724 | 6746 | { |
| 6725 | 6747 | struct case_t *p; |
| 6726 | | − int e; |
| 6727 | | − int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; |
| 6728 | | − while (len > 8) { |
| 6729 | | − /* binary search */ |
| 6730 | | − p = base[len/2]; |
| 6731 | | − vdup(); |
| 6732 | | − if (ll) |
| 6733 | | − vpushll(p->v2); |
| 6734 | | − else |
| 6735 | | − vpushi(p->v2); |
| 6736 | | − gen_op(TOK_LE); |
| 6737 | | − e = gvtst(1, 0); |
| 6738 | | − vdup(); |
| 6739 | | − if (ll) |
| 6740 | | − vpushll(p->v1); |
| 6741 | | − else |
| 6742 | | − vpushi(p->v1); |
| 6743 | | − gen_op(TOK_GE); |
| 6744 | | − gtst_addr(0, p->sym); /* v1 <= x <= v2 */ |
| 6745 | | − /* x < v1 */ |
| 6746 | | − gcase(base, len/2, bsym); |
| 6747 | | − /* x > v2 */ |
| 6748 | | − gsym(e); |
| 6749 | | − e = len/2 + 1; |
| 6750 | | − base += e; len -= e; |
| 6751 | | − } |
| 6752 | | − /* linear scan */ |
| 6753 | | − while (len--) { |
| 6754 | | − p = *base++; |
| 6755 | | − vdup(); |
| 6756 | | − if (ll) |
| 6757 | | − vpushll(p->v2); |
| 6758 | | − else |
| 6759 | | − vpushi(p->v2); |
| 6760 | | − if (p->v1 == p->v2) { |
| 6761 | | − gen_op(TOK_EQ); |
| 6762 | | − gtst_addr(0, p->sym); |
| 6748 | + int t, l2, e; |
| 6749 | + |
| 6750 | + t = vtop->type.t & VT_BTYPE; |
| 6751 | + if (t != VT_LLONG) |
| 6752 | + t = VT_INT; |
| 6753 | + while (len) { |
| 6754 | + /* binary search while len > 8, else linear */ |
| 6755 | + l2 = len > 8 ? len/2 : 0; |
| 6756 | + p = base[l2]; |
| 6757 | + vdup(), vpush64(t, p->v2); |
| 6758 | + if (l2 == 0 && p->v1 == p->v2) { |
| 6759 | + gen_op(TOK_EQ); /* jmp to case when equal */ |
| 6760 | + gsym_addr(gvtst(0, 0), p->ind); |
| 6763 | 6761 | } else { |
| 6764 | | − gen_op(TOK_LE); |
| 6765 | | − e = gvtst(1, 0); |
| 6766 | | − vdup(); |
| 6767 | | − if (ll) |
| 6768 | | − vpushll(p->v1); |
| 6769 | | − else |
| 6770 | | − vpushi(p->v1); |
| 6771 | | − gen_op(TOK_GE); |
| 6772 | | − gtst_addr(0, p->sym); |
| 6762 | + /* case v1 ... v2 */ |
| 6763 | + gen_op(TOK_GT); /* jmp over when > V2 */ |
| 6764 | + if (len == 1) /* last case test jumps to default when false */ |
| 6765 | + dsym = gvtst(0, dsym), e = 0; |
| 6766 | + else |
| 6767 | + e = gvtst(0, 0); |
| 6768 | + vdup(), vpush64(t, p->v1); |
| 6769 | + gen_op(TOK_GE); /* jmp to case when >= V1 */ |
| 6770 | + gsym_addr(gvtst(0, 0), p->ind); |
| 6771 | + dsym = gcase(base, l2, dsym); |
| 6773 | 6772 | gsym(e); |
| 6774 | 6773 | } |
| 6774 | + ++l2, base += l2, len -= l2; |
| 6775 | 6775 | } |
| 6776 | | − *bsym = gjmp(*bsym); |
| 6776 | + /* jump automagically will suppress more jumps */ |
| 6777 | + return gjmp(dsym); |
| 6777 | 6778 | } |
| 6778 | 6779 | |
| 6779 | 6780 | static void end_switch(void) |
| @@ -6791,8 +6792,8 @@ static void try_call_scope_cleanup(Sym *stop) · 11 unmodified lines |
| 6791 | 6792 | { |
| 6792 | 6793 | Sym *cls = cur_scope->cl.s; |
| 6793 | 6794 | |
| 6794 | | − for (; cls != stop; cls = cls->ncl) { |
| 6795 | | − Sym *fs = cls->next; |
| 6795 | + for (; cls != stop; cls = cls->next) { |
| 6796 | + Sym *fs = cls->cleanup_func; |
| 6796 | 6797 | Sym *vs = cls->prev_tok; |
| 6797 | 6798 | |
| 6798 | 6799 | vpushsym(&fs->type, fs); |
| @@ -6814,11 +6815,11 @@ static void try_call_cleanup_goto(Sym *cleanupstate) · 15 unmodified lines |
| 6814 | 6815 | |
| 6815 | 6816 | /* search NCA of both cleanup chains given parents and initial depth */ |
| 6816 | 6817 | ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0; |
| 6817 | | − for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl) |
| 6818 | + for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->next) |
| 6818 | 6819 | ; |
| 6819 | | − for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl) |
| 6820 | + for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->next) |
| 6820 | 6821 | ; |
| 6821 | | − for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd) |
| 6822 | + for (; cc != oc; cc = cc->next, oc = oc->next, --ccd) |
| 6822 | 6823 | ; |
| 6823 | 6824 | |
| 6824 | 6825 | try_call_scope_cleanup(cc); |
| @@ -7153,6 +7154,8 @@ again: · 328 unmodified lines |
| 7153 | 7154 | skip('('); |
| 7154 | 7155 | gexpr(); |
| 7155 | 7156 | skip(')'); |
| 7157 | + if (!is_integer_btype(vtop->type.t & VT_BTYPE)) |
| 7158 | + tcc_error("switch value not an integer"); |
| 7156 | 7159 | sw->sv = *vtop--; /* save switch value */ |
| 7157 | 7160 | a = 0; |
| 7158 | 7161 | b = gjmp(0); /* jump to first case */ |
| @@ -7161,21 +7164,13 @@ again: · 2 unmodified lines |
| 7161 | 7164 | /* case lookup */ |
| 7162 | 7165 | gsym(b); |
| 7163 | 7166 | prev_scope_s(&o); |
| 7164 | | − |
| 7165 | 7167 | if (sw->nocode_wanted) |
| 7166 | 7168 | goto skip_switch; |
| 7167 | | − if (sw->sv.type.t & VT_UNSIGNED) |
| 7168 | | − qsort(sw->p, sw->n, sizeof(void*), case_cmpu); |
| 7169 | | − else |
| 7170 | | − qsort(sw->p, sw->n, sizeof(void*), case_cmpi); |
| 7171 | | − for (b = 1; b < sw->n; b++) |
| 7172 | | − if (sw->sv.type.t & VT_UNSIGNED |
| 7173 | | − ? (uint64_t)sw->p[b - 1]->v2 >= (uint64_t)sw->p[b]->v1 |
| 7174 | | − : sw->p[b - 1]->v2 >= sw->p[b]->v1) |
| 7175 | | − tcc_error("duplicate case value"); |
| 7169 | + case_sort(sw); |
| 7170 | + sw->bsym = NULL; /* marker for 32bit:gen_opl() */ |
| 7176 | 7171 | vpushv(&sw->sv); |
| 7177 | 7172 | gv(RC_INT); |
| 7178 | | − d = 0, gcase(sw->p, sw->n, &d); |
| 7173 | + d = gcase(sw->p, sw->n, 0); |
| 7179 | 7174 | vpop(); |
| 7180 | 7175 | if (sw->def_sym) |
| 7181 | 7176 | gsym_addr(d, sw->def_sym); |
| @@ -7192,17 +7187,18 @@ again: · 10 unmodified lines |
| 7192 | 7187 | expect("switch"); |
| 7193 | 7188 | cr = tcc_malloc(sizeof(struct case_t)); |
| 7194 | 7189 | dynarray_add(&cur_switch->p, &cur_switch->n, cr); |
| 7195 | | − cr->v1 = cr->v2 = expr_const64(); |
| 7196 | | − if (gnu_ext && tok == TOK_DOTS) { |
| 7190 | + t = cur_switch->sv.type.t; |
| 7191 | + cr->v1 = cr->v2 = value64(expr_const64(), t); |
| 7192 | + if (tok == TOK_DOTS && gnu_ext) { |
| 7197 | 7193 | next(); |
| 7198 | | − cr->v2 = expr_const64(); |
| 7199 | | − if ((!(cur_switch->sv.type.t & VT_UNSIGNED) && cr->v2 < cr->v1) |
| 7200 | | − || (cur_switch->sv.type.t & VT_UNSIGNED && (uint64_t)cr->v2 < (uint64_t)cr->v1)) |
| 7194 | + cr->v2 = value64(expr_const64(), t); |
| 7195 | + if (case_cmp(cr->v2, cr->v1) < 0) |
| 7201 | 7196 | tcc_warning("empty case range"); |
| 7202 | 7197 | } |
| 7203 | 7198 | /* case and default are unreachable from a switch under nocode_wanted */ |
| 7204 | 7199 | if (!cur_switch->nocode_wanted) |
| 7205 | | − cr->sym = gind(); |
| 7200 | + cr->ind = gind(); |
| 7201 | + cr->line = file->line_num; |
| 7206 | 7202 | skip(':'); |
| 7207 | 7203 | goto block_after_label; |
| 7208 | 7204 | |
| @@ -7211,7 +7207,7 @@ again: · 2 unmodified lines |
| 7211 | 7207 | expect("switch"); |
| 7212 | 7208 | if (cur_switch->def_sym) |
| 7213 | 7209 | tcc_error("too many 'default'"); |
| 7214 | | − cur_switch->def_sym = cur_switch->nocode_wanted ? 1 : gind(); |
| 7210 | + cur_switch->def_sym = cur_switch->nocode_wanted ? -1 : gind(); |
| 7215 | 7211 | skip(':'); |
| 7216 | 7212 | goto block_after_label; |
| 7217 | 7213 | |
| @@ -7244,7 +7240,7 @@ again: · 26 unmodified lines |
| 7244 | 7240 | s->jnext = gjmp(s->jnext); |
| 7245 | 7241 | } else { |
| 7246 | 7242 | try_call_cleanup_goto(s->cleanupstate); |
| 7247 | | − gjmp_addr(s->jnext); |
| 7243 | + gjmp_addr(s->jind); |
| 7248 | 7244 | } |
| 7249 | 7245 | next(); |
| 7250 | 7246 | |
| @@ -7275,7 +7271,7 @@ again: · 24 unmodified lines |
| 7275 | 7271 | } else { |
| 7276 | 7272 | s = label_push(&global_label_stack, t, LABEL_DEFINED); |
| 7277 | 7273 | } |
| 7278 | | − s->jnext = gind(); |
| 7274 | + s->jind = gind(); |
| 7279 | 7275 | s->cleanupstate = cur_scope->cl.s; |
| 7280 | 7276 | |
| 7281 | 7277 | block_after_label: |
| @@ -8132,8 +8128,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 850 unmodified lines |
| 8132 | 8128 | Sym *cls = sym_push2(&all_cleanups, |
| 8133 | 8129 | SYM_FIELD | ++cur_scope->cl.n, 0, 0); |
| 8134 | 8130 | cls->prev_tok = sym; |
| 8135 | | − cls->next = ad->cleanup_func; |
| 8136 | | − cls->ncl = cur_scope->cl.s; |
| 8131 | + cls->cleanup_func = ad->cleanup_func; |
| 8132 | + cls->next = cur_scope->cl.s; |
| 8137 | 8133 | cur_scope->cl.s = cls; |
| 8138 | 8134 | } |
| 8139 | 8135 | |