]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390: Do not waste a register when assigning a constant to a memory
authorFlorian Krohm <florian@eich-krohm.de>
Thu, 27 Dec 2012 00:59:43 +0000 (00:59 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Thu, 27 Dec 2012 00:59:43 +0000 (00:59 +0000)
location. If available, use MVHI and friends. If those are not available,
load the constant value into register r0 and store that. r0 is not visible
to register allocation and therefore using it does not increase register
pressure.
Remove S390_INSN_MZERO and replace it with S390_INSN_MIMM. Assigning zero
is just a special case..
Saves between 0.9% and 2.4% of insns as measured with the perf regression
bucket.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2619

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

index 3a822222bafd0686f3895752caf136a28f0e9ea2..adea62e7402a5208c8cf20b365c735163840f8b1 100644 (file)
@@ -741,8 +741,8 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
          addHRegUse(u, HRmRead, insn->variant.dfp_convert.op_lo); /* operand */
       break;
 
-   case S390_INSN_MZERO:
-      s390_amode_get_reg_usage(u, insn->variant.mzero.dst);
+   case S390_INSN_MIMM:
+      s390_amode_get_reg_usage(u, insn->variant.mimm.dst);
       break;
 
    case S390_INSN_MADD:
@@ -1026,8 +1026,8 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
             lookupHRegRemap(m, insn->variant.dfp_convert.op_lo);
       break;
 
-   case S390_INSN_MZERO:
-      s390_amode_map_regs(m, insn->variant.mzero.dst);
+   case S390_INSN_MIMM:
+      s390_amode_map_regs(m, insn->variant.mimm.dst);
       break;
 
    case S390_INSN_MADD:
@@ -1309,6 +1309,32 @@ emit_S(UChar *p, UInt op, UChar b2, UShort d2)
 }
 
 
+static UChar *
+emit_SI(UChar *p, UInt op, UChar i2, UChar b1, UShort d1)
+{
+   ULong the_insn = op;
+
+   the_insn |= ((ULong)i2) << 16;
+   the_insn |= ((ULong)b1) << 12;
+   the_insn |= ((ULong)d1) << 0;
+
+   return emit_4bytes(p, the_insn);
+}
+
+
+static UChar *
+emit_SIL(UChar *p, ULong op, UChar b1, UShort d1, UShort i2)
+{
+   ULong the_insn = op;
+
+   the_insn |= ((ULong)b1) << 28;
+   the_insn |= ((ULong)d1) << 16;
+   the_insn |= ((ULong)i2) << 0;
+
+   return emit_6bytes(p, the_insn);
+}
+
+
 static UChar *
 emit_SIY(UChar *p, ULong op, UChar i2, UChar b1, UShort dl1, UChar dh1)
 {
@@ -2734,6 +2760,46 @@ s390_emit_MSGFI(UChar *p, UChar r1, UInt i2)
 }
 
 
+static UChar *
+s390_emit_MVI(UChar *p, UChar i2, UChar b1, UShort d1)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC3(MNM, UDXB, INT), "mvi", b1, 0, d1, i2);
+
+   return emit_SI(p, 0x92000000, i2, b1, d1);
+}
+
+
+static UChar *
+s390_emit_MVHHI(UChar *p, UChar b1, UShort d1, UShort i2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC3(MNM, UDXB, INT), "mvhhi", b1, 0, d1, i2);
+
+   return emit_SIL(p, 0xe54400000000ULL, b1, d1, i2);
+}
+
+
+static UChar *
+s390_emit_MVHI(UChar *p, UChar b1, UShort d1, UShort i2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC3(MNM, UDXB, INT), "mvhi", b1, 0, d1, i2);
+
+   return emit_SIL(p, 0xe54c00000000ULL, b1, d1, i2);
+}
+
+
+static UChar *
+s390_emit_MVGHI(UChar *p, UChar b1, UShort d1, UShort i2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC3(MNM, UDXB, INT), "mvghi", b1, 0, d1, i2);
+
+   return emit_SIL(p, 0xe54800000000ULL, b1, d1, i2);
+}
+
+
 static UChar *
 s390_emit_OR(UChar *p, UChar r1, UChar r2)
 {
@@ -5472,17 +5538,18 @@ s390_insn_mfence(void)
 
 
 s390_insn *
-s390_insn_mzero(UChar size, s390_amode *dst)
+s390_insn_mimm(UChar size, s390_amode *dst, ULong value)
 {
    s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
 
-   /* This insn will be mapped to an XC so we can only allow base register
+   /* This insn will be mapped to insns that require base register
       plus 12-bit displacement */
    vassert(dst->tag == S390_AMODE_B12);
 
-   insn->tag  = S390_INSN_MZERO;
+   insn->tag  = S390_INSN_MIMM;
    insn->size = size;
-   insn->variant.mzero.dst = dst;
+   insn->variant.mimm.dst = dst;
+   insn->variant.mimm.value = value;
 
    return insn;
 }
@@ -6074,8 +6141,9 @@ s390_insn_as_string(const s390_insn *insn)
       s390_sprintf(buf, "%M", "v-mfence");
       return buf;   /* avoid printing "size = ..." which is meaningless */
 
-   case S390_INSN_MZERO:
-      s390_sprintf(buf, "%M %A", "v-mzero", insn->variant.mzero.dst);
+   case S390_INSN_MIMM:
+      s390_sprintf(buf, "%M %A,%I", "v-mimm", insn->variant.mimm.dst,
+                   insn->variant.mimm.value);
       break;
 
    case S390_INSN_MADD:
@@ -8305,11 +8373,42 @@ s390_insn_mfence_emit(UChar *buf, const s390_insn *insn)
 
 
 static UChar *
-s390_insn_mzero_emit(UChar *buf, const s390_insn *insn)
+s390_insn_mimm_emit(UChar *buf, const s390_insn *insn)
 {
-   s390_amode *am = insn->variant.mzero.dst;
+   s390_amode *am = insn->variant.mimm.dst;
+   ULong value = insn->variant.mimm.value;
 
-   return s390_emit_XC(buf, insn->size - 1, am->b, am->d, am->b, am->d);
+   if (value == 0) {
+      return s390_emit_XC(buf, insn->size - 1, am->b, am->d, am->b, am->d);
+   }
+
+   if (insn->size == 1) {
+      return s390_emit_MVI(buf, value & 0xFF, am->b, am->d);
+   }
+
+   if (s390_host_has_gie && ulong_fits_signed_16bit(value)) {
+      value &= 0xFFFF;
+      switch (insn->size) {
+      case 2: return s390_emit_MVHHI(buf, am->b, am->d, value);
+      case 4: return s390_emit_MVHI(buf,  am->b, am->d, value);
+      case 8: return s390_emit_MVGHI(buf, am->b, am->d, value);
+      }
+   } else {
+      // Load value to R0, then store.
+      switch (insn->size) {
+      case 2:
+         buf = s390_emit_LHI(buf, R0, value & 0xFFFF);
+         return s390_emit_STH(buf, R0, 0, am->b, am->d);
+      case 4:
+         buf = s390_emit_load_32imm(buf, R0, value);
+         return s390_emit_ST(buf, R0, 0, am->b, am->d);
+      case 8:
+         buf = s390_emit_load_64imm(buf, R0, value);
+         return s390_emit_STG(buf, R0, 0, am->b, DISP20(am->d));
+      }
+   }
+   
+   vpanic("s390_insn_mimm_emit");
 }
 
 
@@ -8912,8 +9011,8 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn,
       end = s390_insn_mfence_emit(buf, insn);
       break;
 
-   case S390_INSN_MZERO:
-      end = s390_insn_mzero_emit(buf, insn);
+   case S390_INSN_MIMM:
+      end = s390_insn_mimm_emit(buf, insn);
       break;
 
    case S390_INSN_MADD:
index 4b795c4a80fbfc761b66b2963b68733abc9ffd0a..56b8b126bb4e68c93e9df3245a1b4a17c7139a1e 100644 (file)
@@ -144,7 +144,7 @@ typedef enum {
    S390_INSN_DFP_COMPARE,
    S390_INSN_DFP_CONVERT,
    S390_INSN_MFENCE,
-   S390_INSN_MZERO,   /* Assign zero to a memory location */
+   S390_INSN_MIMM,    /* Assign an immediate constant to a memory location */
    S390_INSN_MADD,    /* Add a value to a memory location */
    S390_INSN_SET_FPC_BFPRM, /* Set the bfp rounding mode in the FPC */
    S390_INSN_SET_FPC_DFPRM, /* Set the dfp rounding mode in the FPC */
@@ -463,7 +463,8 @@ typedef struct {
       /* Miscellaneous */
       struct {
          s390_amode      *dst;
-      } mzero;
+         ULong            value;  /* sign extended */
+      } mimm;
       struct {
          s390_amode      *dst;
          UChar            delta;
@@ -584,7 +585,7 @@ s390_insn *s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t,
                                          HReg dst, HReg op_hi, HReg op_lo,
                                          s390_dfp_round_t);
 s390_insn *s390_insn_mfence(void);
-s390_insn *s390_insn_mzero(UChar size, s390_amode *dst);
+s390_insn *s390_insn_mimm(UChar size, s390_amode *dst, ULong value);
 s390_insn *s390_insn_madd(UChar size, s390_amode *dst, UChar delta,
                           ULong value);
 s390_insn *s390_insn_set_fpc_bfprm(UChar size, HReg mode);
index 3027045049418493b38d03b865b6dfc2de6f97d2..ce81ceeb890f18e1e382373beb569e64004a4fd2 100644 (file)
@@ -426,6 +426,24 @@ s390_expr_is_const_zero(IRExpr *expr)
 }
 
 
+/* Return the value of CON as a sign-exteded ULong value */
+static ULong
+get_const_value_as_ulong(const IRConst *con)
+{
+   Long value;
+
+   switch (con->tag) {
+   case Ico_U1:  value = con->Ico.U1;  return (ULong) ((value << 63) >> 63);
+   case Ico_U8:  value = con->Ico.U8;  return (ULong) ((value << 56) >> 56);
+   case Ico_U16: value = con->Ico.U16; return (ULong) ((value << 48) >> 48);
+   case Ico_U32: value = con->Ico.U32; return (ULong) ((value << 32) >> 32);
+   case Ico_U64: return con->Ico.U64;
+   default:
+      vpanic("get_const_value_as_ulong");
+   }
+}
+
+
 /* Call a helper (clean or dirty)
    Arguments must satisfy the following conditions:
 
@@ -2924,8 +2942,10 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
       case Ity_I64:
          /* fixs390: We could check for INSN_MADD here. */
          if (am->tag == S390_AMODE_B12 &&
-             s390_expr_is_const_zero(stmt->Ist.Store.data)) {
-            addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
+             stmt->Ist.Store.data->tag == Iex_Const) {
+            ULong value =
+               get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
+            addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
             return;
          }
          src = s390_isel_int_expr(env, stmt->Ist.Store.data);
@@ -3000,13 +3020,6 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
          return;
       }
 
-      /* guest register = 0 */
-      if (new_value == 0) {
-         am = s390_amode_for_guest_state(offset);
-         addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
-         return;
-      }
-
       if (old_value_is_valid == False) goto not_special;
 
       /* If the new value is in the neighbourhood of the old value
@@ -3020,22 +3033,17 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
          return;
       }
 
-      /* If the high word is the same it is sufficient to load the low word.
-         Use R0 as a scratch reg. */
+      /* If the high word is the same it is sufficient to load the low word. */
       if ((old_value >> 32) == (new_value >> 32)) {
-         HReg r0  = make_gpr(0);
-
          am = s390_amode_for_guest_state(offset + 4);
-         addInstr(env, s390_insn_load_immediate(4, r0,
-                                                new_value & 0xFFFFFFFF));
-         addInstr(env, s390_insn_store(4, am, r0));
+         addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
          return;
       }
 
       /* No special case applies... fall through */
 
    not_special:
-      am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
+      am = s390_amode_for_guest_state(offset);
 
       switch (tyd) {
       case Ity_I8:
@@ -3043,8 +3051,10 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
       case Ity_I32:
       case Ity_I64:
          if (am->tag == S390_AMODE_B12 &&
-             s390_expr_is_const_zero(stmt->Ist.Put.data)) {
-            addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
+             stmt->Ist.Put.data->tag == Iex_Const) {
+            ULong value =
+               get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
+            addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
             return;
          }
          src = s390_isel_int_expr(env, stmt->Ist.Put.data);