From: Andreas Arnez Date: Thu, 26 Mar 2026 12:33:17 +0000 (+0100) Subject: s390x: Exploit "load address" in isel X-Git-Tag: VALGRIND_3_27_0~58 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=b3830b82f455f06ed8a0bf59990b5a2b0b0bbcfd;p=thirdparty%2Fvalgrind.git s390x: Exploit "load address" in isel Compared to AGHI, the "load address" instrucions LA and LAY can be beneficial for register allocation since they allow for distinct source and destination operands. This can often avoid unnecessary register moves. Exploit them when appropriate in isel. --- diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 691978d20..fe0e7380b 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -2587,6 +2587,20 @@ s390_emit_LY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2) } +static UChar * +s390_emit_LA(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2) +{ + return emit_RX(p, 0x41000000, r1, x2, b2, d2); +} + + +static UChar * +s390_emit_LAY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2) +{ + return emit_RXY(p, 0xe30000000071ULL, r1, x2, b2, dl2, dh2); +} + + static UChar * s390_emit_LG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2) { @@ -6353,6 +6367,10 @@ s390_insn_as_string(const s390_insn *insn) op = "v-signx"; break; + case S390_LOAD_ADDRESS: + op = "v-laddr"; + break; + case S390_NEGATE: op = "v-neg"; break; @@ -8050,7 +8068,24 @@ s390_insn_unop_emit(UChar *buf, const s390_insn *insn) case S390_SIGN_EXTEND_16: return s390_widen_emit(buf, insn, 2, 1); case S390_SIGN_EXTEND_32: return s390_widen_emit(buf, insn, 4, 1); - case S390_NEGATE: return s390_negate_emit(buf, insn); + case S390_LOAD_ADDRESS: { + vassert(insn->variant.unop.src.tag == S390_OPND_AMODE); + UChar dst = hregNumber(insn->variant.unop.dst); + s390_amode* am = insn->variant.unop.src.variant.am; + UChar x = hregNumber(am->x); + UChar b = hregNumber(am->b); + switch (am->tag) { + case S390_AMODE_B12: + case S390_AMODE_BX12: + return s390_emit_LA(buf, dst, x, b, am->d); + case S390_AMODE_B20: + case S390_AMODE_BX20: + return s390_emit_LAY(buf, dst, x, b, DISP20(am->d)); + } + vpanic("s390_insn_unop_emit -- load address"); + } + case S390_NEGATE: + return s390_negate_emit(buf, insn); case S390_POPCNT: return s390_popcnt_emit(buf, insn); case S390_VEC_FILL: { vassert(insn->variant.unop.src.tag == S390_OPND_IMMEDIATE); diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index 2a5d7a4f7..8b8812956 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -201,6 +201,7 @@ typedef enum { S390_SIGN_EXTEND_8, S390_SIGN_EXTEND_16, S390_SIGN_EXTEND_32, + S390_LOAD_ADDRESS, S390_NEGATE, S390_POPCNT, S390_VEC_FILL, diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 04a2e053e..9e34afffc 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -1713,6 +1713,22 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) } } + /* Is this a match for "load address"? */ + if (expr->Iex.Binop.op == Iop_Add64) { + ULong disp = arg2->Iex.Const.con->Ico.U64; + if (arg2->tag == Iex_Const && ulong_fits_signed_20bit(disp)) { + h1 = s390_isel_int_expr(env, arg1); + opnd.tag = S390_OPND_AMODE; + if (ulong_fits_unsigned_12bit(disp)) { + opnd.variant.am = s390_amode_b12(disp, h1); + } else { + opnd.variant.am = s390_amode_b20((Int)disp, h1); + } + addInstr(env, s390_insn_unop(size, S390_LOAD_ADDRESS, res, opnd)); + return res; + } + } + h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */