]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Exploit "load address" in isel
authorAndreas Arnez <arnez@linux.ibm.com>
Thu, 26 Mar 2026 12:33:17 +0000 (13:33 +0100)
committerAndreas Arnez <arnez@linux.ibm.com>
Thu, 26 Mar 2026 12:33:17 +0000 (13:33 +0100)
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.

VEX/priv/host_s390_defs.c
VEX/priv/host_s390_defs.h
VEX/priv/host_s390_isel.c

index 691978d20217294860e2736bd72ac141eba06b65..fe0e7380b22066f78654d8175e047993094812dd 100644 (file)
@@ -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);
index 2a5d7a4f73986ef7409371a10270b15a2d44f02e..8b8812956713383b24e2881ac3835b371b672f70 100644 (file)
@@ -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,
index 04a2e053eb0beda04172222be5952dac8c7120d9..9e34afffc073c2ed5609c742c41268dac73813d2 100644 (file)
@@ -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 */