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

View File

@ -5150,41 +5150,17 @@ 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) {
if (tok != ':' || !gnu_ext) {
vpop();
gexpr();
}
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 /* needed to avoid having different registers saved in
each branch */ each branch */
if (is_float(vtop->type.t)) { if (is_float(vtop->type.t)) {
@ -5194,28 +5170,42 @@ static void expr_cond(void)
rc = RC_ST0; rc = RC_ST0;
} }
#endif #endif
} } else
else
rc = RC_INT; rc = RC_INT;
gv(rc);
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 { } else {
tt = gvtst(1, 0); if (!g)
gexpr(); vpop();
tt = 0;
} }
if (1) {
if (c == 0)
nocode_wanted = 1;
if (!g)
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 = 0;
if (c < 0)
u = gjmp(0); u = gjmp(0);
gsym(tt); gsym(tt);
nocode_wanted = saved_nocode_wanted;
if (c == 1)
nocode_wanted = 1;
expr_cond(); expr_cond();
type2 = vtop->type; 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 */
if (c != 1) {
gen_cast(&type); gen_cast(&type);
if (islv) { if (islv) {
mk_pointer(&vtop->type); mk_pointer(&vtop->type);
gaddrof(); gaddrof();
} } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof(); gaddrof();
}
rc = RC_INT; rc = RC_INT;
if (is_float(type.t)) { if (is_float(type.t)) {
rc = RC_FLOAT; rc = RC_FLOAT;
@ -5290,23 +5284,33 @@ static void expr_cond(void)
rc = RC_IRET; rc = RC_IRET;
} }
tt = r2 = 0;
if (c < 0) {
r2 = gv(rc); 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 */
*vtop = sv;
gen_cast(&type); gen_cast(&type);
if (islv) { if (islv) {
mk_pointer(&vtop->type); mk_pointer(&vtop->type);
gaddrof(); gaddrof();
} } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof(); gaddrof();
}
if (c != 0)
vswap();
vtop--;
if (c < 0) {
r1 = gv(rc); r1 = gv(rc);
move_reg(r2, r1, type.t); move_reg(r2, r1, type.t);
vtop->r = r2; vtop->r = r2;
}
gsym(tt); gsym(tt);
if (islv) if (islv)
indir(); indir();