tcg/s390: Fix setcond expansion

We can't use LOAD AND TEST for unsigned data and then expect to
extract the result with ADD LOGICAL WITH CARRY. Fall through to
using COMPARE LOGICAL IMMEDIATE instead.

Backports commit 65839b56b9a740e6b898b5d81afc160502bd2935 from qemu
This commit is contained in:
Richard Henderson 2018-03-01 11:04:30 -05:00 committed by Lioncash
parent eb489625b5
commit 7852cc600d
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -1098,33 +1098,43 @@ static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
} }
static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
TCGArg c2, int c2const) TCGArg c2, bool c2const, bool need_carry)
{ {
bool is_unsigned = is_unsigned_cond(c); bool is_unsigned = is_unsigned_cond(c);
if (c2const) { if (c2const) {
if (c2 == 0) { if (c2 == 0) {
if (type == TCG_TYPE_I32) { if (!(is_unsigned && need_carry)) {
tcg_out_insn(s, RR, LTR, r1, r1); if (type == TCG_TYPE_I32) {
} else { tcg_out_insn(s, RR, LTR, r1, r1);
tcg_out_insn(s, RRE, LTGR, r1, r1); } else {
tcg_out_insn(s, RRE, LTGR, r1, r1);
}
return tcg_cond_to_ltr_cond[c];
} }
return tcg_cond_to_ltr_cond[c]; /* If we only got here because of load-and-test,
} else { and we couldn't use that, then we need to load
if (is_unsigned) { the constant into a register. */
if (type == TCG_TYPE_I32) { if (!(facilities & FACILITY_EXT_IMM)) {
tcg_out_insn(s, RIL, CLFI, r1, c2); c2 = TCG_TMP0;
} else { tcg_out_movi(s, type, c2, 0);
tcg_out_insn(s, RIL, CLGFI, r1, c2); goto do_reg;
} }
}
if (is_unsigned) {
if (type == TCG_TYPE_I32) {
tcg_out_insn(s, RIL, CLFI, r1, c2);
} else { } else {
if (type == TCG_TYPE_I32) { tcg_out_insn(s, RIL, CLGFI, r1, c2);
tcg_out_insn(s, RIL, CFI, r1, c2); }
} else { } else {
tcg_out_insn(s, RIL, CGFI, r1, c2); if (type == TCG_TYPE_I32) {
} tcg_out_insn(s, RIL, CFI, r1, c2);
} else {
tcg_out_insn(s, RIL, CGFI, r1, c2);
} }
} }
} else { } else {
do_reg:
if (is_unsigned) { if (is_unsigned) {
if (type == TCG_TYPE_I32) { if (type == TCG_TYPE_I32) {
tcg_out_insn(s, RR, CLR, r1, c2); tcg_out_insn(s, RR, CLR, r1, c2);
@ -1153,7 +1163,7 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
do_greater: do_greater:
/* The result of a compare has CC=2 for GT and CC=3 unused. /* The result of a compare has CC=2 for GT and CC=3 unused.
ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */ ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */
tgen_cmp(s, type, cond, c1, c2, c2const); tgen_cmp(s, type, cond, c1, c2, c2const, true);
tcg_out_movi(s, type, dest, 0); tcg_out_movi(s, type, dest, 0);
tcg_out_insn(s, RRE, ALCGR, dest, dest); tcg_out_insn(s, RRE, ALCGR, dest, dest);
return; return;
@ -1224,7 +1234,7 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
break; break;
} }
cc = tgen_cmp(s, type, cond, c1, c2, c2const); cc = tgen_cmp(s, type, cond, c1, c2, c2const, false);
if (facilities & FACILITY_LOAD_ON_COND) { if (facilities & FACILITY_LOAD_ON_COND) {
/* Emit: d = 0, t = 1, d = (cc ? t : d). */ /* Emit: d = 0, t = 1, d = (cc ? t : d). */
tcg_out_movi(s, TCG_TYPE_I64, dest, 0); tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
@ -1243,11 +1253,11 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest,
{ {
int cc; int cc;
if (facilities & FACILITY_LOAD_ON_COND) { if (facilities & FACILITY_LOAD_ON_COND) {
cc = tgen_cmp(s, type, c, c1, c2, c2const); cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
tcg_out_insn(s, RRF, LOCGR, dest, r3, cc); tcg_out_insn(s, RRF, LOCGR, dest, r3, cc);
} else { } else {
c = tcg_invert_cond(c); c = tcg_invert_cond(c);
cc = tgen_cmp(s, type, c, c1, c2, c2const); cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
/* Emit: if (cc) goto over; dest = r3; over: */ /* Emit: if (cc) goto over; dest = r3; over: */
tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
@ -1379,7 +1389,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
} }
} }
cc = tgen_cmp(s, type, c, r1, c2, c2const); cc = tgen_cmp(s, type, c, r1, c2, c2const, false);
tgen_branch(s, cc, l); tgen_branch(s, cc, l);
} }