tccgen: fix expr_cond for alt. nocode_wanted

making shure that both the active and the passive branches
do exacly the same thing.
master
grischka 2016-12-18 18:55:55 +01:00
parent f843cadb6b
commit e5efd18435
1 changed files with 76 additions and 72 deletions

148
tccgen.c
View File

@ -5150,72 +5150,62 @@ static int condition_3way(void)
static void expr_cond(void) static void expr_cond(void)
{ {
int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv; int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g;
int c;
SValue sv; SValue sv;
CType type, type1, type2; CType type, type1, type2;
int saved_nocode_wanted = nocode_wanted;
expr_lor(); expr_lor();
if (tok == '?') { if (tok == '?') {
next(); next();
c = condition_3way(); c = condition_3way();
if (c >= 0) { g = (tok == ':' && gnu_ext);
int saved_nocode_wanted = nocode_wanted; if (c < 0) {
if (c) { /* needed to avoid having different registers saved in
if (tok != ':' || !gnu_ext) { each branch */
vpop(); if (is_float(vtop->type.t)) {
gexpr(); rc = RC_FLOAT;
}
skip(':');
nocode_wanted = 1;
expr_cond();
vpop();
nocode_wanted = saved_nocode_wanted;
} else {
vpop();
if (tok != ':' || !gnu_ext) {
nocode_wanted = 1;
gexpr();
vpop();
nocode_wanted = saved_nocode_wanted;
}
skip(':');
expr_cond();
}
}
else {
if (vtop != vstack) {
/* needed to avoid having different registers saved in
each branch */
if (is_float(vtop->type.t)) {
rc = RC_FLOAT;
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
rc = RC_ST0; rc = RC_ST0;
}
#endif
} }
else #endif
rc = RC_INT; } else
gv(rc); rc = RC_INT;
save_regs(1); save_regs(1);
} gv(rc);
if (tok == ':' && gnu_ext) { if (g)
gv_dup(); gv_dup();
tt = gvtst(1, 0); tt = gvtst(1, 0);
} else {
tt = gvtst(1, 0); } else {
if (!g)
vpop();
tt = 0;
}
if (1) {
if (c == 0)
nocode_wanted = 1;
if (!g)
gexpr(); gexpr();
}
type1 = vtop->type; type1 = vtop->type;
sv = *vtop; /* save value to handle it later */ sv = *vtop; /* save value to handle it later */
vtop--; /* no vpop so that FP stack is not flushed */ vtop--; /* no vpop so that FP stack is not flushed */
skip(':'); skip(':');
u = gjmp(0);
gsym(tt);
expr_cond();
type2 = vtop->type;
u = 0;
if (c < 0)
u = gjmp(0);
gsym(tt);
nocode_wanted = saved_nocode_wanted;
if (c == 1)
nocode_wanted = 1;
expr_cond();
nocode_wanted = saved_nocode_wanted;
type2 = vtop->type;
t1 = type1.t; t1 = type1.t;
bt1 = t1 & VT_BTYPE; bt1 = t1 & VT_BTYPE;
t2 = type2.t; t2 = type2.t;
@ -5224,6 +5214,7 @@ static void expr_cond(void)
if (is_float(bt1) || is_float(bt2)) { if (is_float(bt1) || is_float(bt2)) {
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
type.t = VT_LDOUBLE; type.t = VT_LDOUBLE;
} else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
type.t = VT_DOUBLE; type.t = VT_DOUBLE;
} else { } else {
@ -5267,15 +5258,18 @@ static void expr_cond(void)
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
that `(expr ? a : b).mem` does not error with "lvalue expected" */ that `(expr ? a : b).mem` does not error with "lvalue expected" */
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
islv &= c < 0;
/* now we convert second operand */ /* now we convert second operand */
gen_cast(&type); if (c != 1) {
if (islv) { gen_cast(&type);
mk_pointer(&vtop->type); if (islv) {
gaddrof(); mk_pointer(&vtop->type);
gaddrof();
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
} }
else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
rc = RC_INT; rc = RC_INT;
if (is_float(type.t)) { if (is_float(type.t)) {
rc = RC_FLOAT; rc = RC_FLOAT;
@ -5287,26 +5281,36 @@ static void expr_cond(void)
} else if ((type.t & VT_BTYPE) == VT_LLONG) { } else if ((type.t & VT_BTYPE) == VT_LLONG) {
/* for long longs, we use fixed registers to avoid having /* for long longs, we use fixed registers to avoid having
to handle a complicated move */ to handle a complicated move */
rc = RC_IRET; rc = RC_IRET;
} }
r2 = gv(rc); tt = r2 = 0;
if (c < 0) {
r2 = gv(rc);
tt = gjmp(0);
}
gsym(u);
/* this is horrible, but we must also convert first /* this is horrible, but we must also convert first
operand */ operand */
tt = gjmp(0); vpushv(&sv);
gsym(u); if (c != 2) {
/* put again first value and cast it */ gen_cast(&type);
*vtop = sv; if (islv) {
gen_cast(&type); mk_pointer(&vtop->type);
if (islv) { gaddrof();
mk_pointer(&vtop->type); } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof(); gaddrof();
}
if (c != 0)
vswap();
vtop--;
if (c < 0) {
r1 = gv(rc);
move_reg(r2, r1, type.t);
vtop->r = r2;
} }
else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
r1 = gv(rc);
move_reg(r2, r1, type.t);
vtop->r = r2;
gsym(tt); gsym(tt);
if (islv) if (islv)
indir(); indir();