]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Introduce and exploit new ALU operator S390_ALU_ILIH
authorAndreas Arnez <arnez@linux.ibm.com>
Thu, 2 Apr 2020 16:00:13 +0000 (18:00 +0200)
committerAndreas Arnez <arnez@linux.ibm.com>
Wed, 8 Apr 2020 17:39:28 +0000 (19:39 +0200)
The handlers of Iop_8HLto16, Iop16HLto32, and Iop_32HLto64 in
s390_isel_int_wrk() yield a sequence of "shift", "and", and "or" ALU
operations, the second of which modifies a register returned from a call
to s390_isel_int_expr().  While this approach does not lead to wrong code
generation (because only the register's upper bits are changed which are
not relevant to the IR type), it violates the general "no-modify" rule.

Replace this sequence of ALU operations by a single ALU operation
S390_ALU_ILIH that inserts the low half of its second operand into the
high half of its first operand.  Use the z/Architecture instruction
RISBG ("rotate then insert selected bits") for implementating it.

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

index 308b6ff409a9db9fb6907cd85cddc6c919f93b4e..3b6121fec3fd7ed4a547506eddfff373033f9edb 100644 (file)
@@ -1508,6 +1508,22 @@ emit_RIE(UChar *p, ULong op, UChar r1, UShort i2, UChar m3)
 }
 
 
+static UChar *
+emit_RIEf(UChar *p, ULong op, UChar r1, UChar r2,
+          UChar i3, Char i4, UChar i5)
+{
+   ULong the_insn = op;
+
+   the_insn |= ((ULong)r1) << 36;
+   the_insn |= ((ULong)r2) << 32;
+   the_insn |= ((ULong)i3) << 24;
+   the_insn |= ((ULong)i4) << 16;
+   the_insn |= ((ULong)i5) << 8;
+
+   return emit_6bytes(p, the_insn);
+}
+
+
 static UChar *
 emit_RR(UChar *p, UInt op, UChar r1, UChar r2)
 {
@@ -5265,6 +5281,16 @@ s390_emit_LOCGHI(UChar *p, UChar r1, UShort i2, UChar m3)
    return emit_RIE(p, 0xec0000000046ULL, r1, i2, m3);
 }
 
+static UChar *
+s390_emit_RISBG(UChar *p, UChar r1, UChar r2, UChar i3, Char i4, UChar i5)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC6(MNM, GPR, GPR, UINT, UINT, UINT),
+                  "risbg", r1, r2, i3, i4, i5);
+
+   return emit_RIEf(p, 0xec0000000055ULL, r1, r2, i3, i4, i5);
+}
+
 
 /* Provide a symbolic name for register "R0" */
 #define R0 0
@@ -7759,6 +7785,7 @@ s390_insn_as_string(const s390_insn *insn)
       case S390_ALU_LSH:  op = "v-lsh";  break;
       case S390_ALU_RSH:  op = "v-rsh";  break;
       case S390_ALU_RSHA: op = "v-rsha"; break;
+      case S390_ALU_ILIH: op = "v-ilih"; break;
       default: goto fail;
       }
       s390_sprintf(buf, "%M %R,%O", op, insn->variant.alu.dst, /* also op1 */
@@ -8677,6 +8704,24 @@ s390_insn_load_immediate_emit(UChar *buf, const s390_insn *insn)
 }
 
 
+/* Insert low half of r2 into high half of dst. */
+static UChar *
+s390_emit_ilih(UChar *buf, UChar size, UChar dst, UChar r2)
+{
+   if (s390_host_has_gie)
+      return s390_emit_RISBG(buf, dst, r2, 64 - 8 * size, 63 - 4 * size,
+                             4 * size);
+
+   /* Clear dst's upper half. */
+   buf = s390_emit_SLLG(buf, dst, dst, 0, DISP20(64 - 4 * size));
+   buf = s390_emit_SRLG(buf, dst, dst, 0, DISP20(64 - 4 * size));
+
+   /* Shift r2 by appropriate amount and OR it into dst. */
+   buf = s390_emit_SLLG(buf, R0, r2, 0, DISP20(4 * size));
+   return s390_emit_OGR(buf, dst, R0);
+}
+
+
 /* There is no easy way to do ALU operations on 1-byte or 2-byte operands.
    So we simply perform a 4-byte operation. Doing so uses possibly undefined
    bits and produces an undefined result in those extra bit positions. But
@@ -8708,6 +8753,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
          case S390_ALU_LSH:  return s390_emit_SLL(buf, dst, r2, 0);
          case S390_ALU_RSH:  return s390_emit_SRL(buf, dst, r2, 0);
          case S390_ALU_RSHA: return s390_emit_SRA(buf, dst, r2, 0);
+         case S390_ALU_ILIH: return s390_emit_ilih(buf, insn->size, dst, r2);
          }
          goto fail;
 
@@ -8722,6 +8768,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
          case S390_ALU_LSH:  return s390_emit_SLLG(buf, dst, dst, r2, DISP20(0));
          case S390_ALU_RSH:  return s390_emit_SRLG(buf, dst, dst, r2, DISP20(0));
          case S390_ALU_RSHA: return s390_emit_SRAG(buf, dst, dst, r2, DISP20(0));
+         case S390_ALU_ILIH: return s390_emit_ilih(buf, 8, dst, r2);
          }
          goto fail;
       }
@@ -8802,6 +8849,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
          case S390_ALU_AND: return s390_emit_NR(buf, dst, R0);
          case S390_ALU_OR:  return s390_emit_OR(buf, dst, R0);
          case S390_ALU_XOR: return s390_emit_XR(buf, dst, R0);
+         case S390_ALU_ILIH:
          case S390_ALU_LSH:
          case S390_ALU_RSH:
          case S390_ALU_RSHA: ; /* avoid GCC warning */
@@ -8836,6 +8884,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
                buf = s390_emit_LH(buf, R0, x, b, d);
                return s390_emit_XR(buf, dst, R0);
 
+            case S390_ALU_ILIH:
             case S390_ALU_LSH:
             case S390_ALU_RSH:
             case S390_ALU_RSHA: ; /* avoid GCC warning */
@@ -8868,6 +8917,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
                buf = s390_emit_LHY(buf, R0, x, b, DISP20(d));
                return s390_emit_XR(buf, dst, R0);
 
+            case S390_ALU_ILIH:
             case S390_ALU_LSH:
             case S390_ALU_RSH:
             case S390_ALU_RSHA: ; /* avoid GCC warning */
@@ -8887,6 +8937,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
             case S390_ALU_AND: return s390_emit_N(buf, dst, x, b, d);
             case S390_ALU_OR:  return s390_emit_O(buf, dst, x, b, d);
             case S390_ALU_XOR: return s390_emit_X(buf, dst, x, b, d);
+            case S390_ALU_ILIH:
             case S390_ALU_LSH:
             case S390_ALU_RSH:
             case S390_ALU_RSHA: ; /* avoid GCC warning */
@@ -8902,6 +8953,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
             case S390_ALU_AND: return s390_emit_NY(buf, dst, x, b, DISP20(d));
             case S390_ALU_OR:  return s390_emit_OY(buf, dst, x, b, DISP20(d));
             case S390_ALU_XOR: return s390_emit_XY(buf, dst, x, b, DISP20(d));
+            case S390_ALU_ILIH:
             case S390_ALU_LSH:
             case S390_ALU_RSH:
             case S390_ALU_RSHA: ; /* avoid GCC warning */
@@ -8918,6 +8970,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
          case S390_ALU_AND: return s390_emit_NG(buf, dst, x, b, DISP20(d));
          case S390_ALU_OR:  return s390_emit_OG(buf, dst, x, b, DISP20(d));
          case S390_ALU_XOR: return s390_emit_XG(buf, dst, x, b, DISP20(d));
+         case S390_ALU_ILIH:
          case S390_ALU_LSH:
          case S390_ALU_RSH:
          case S390_ALU_RSHA: ; /* avoid GCC warning */
@@ -8965,6 +9018,8 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
 
          case S390_ALU_RSHA:
             return s390_emit_SRA(buf, dst, 0, value);
+
+         case S390_ALU_ILIH: ; /* avoid GCC warning */
          }
          goto fail;
 
@@ -8984,6 +9039,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
          case S390_ALU_LSH:  return s390_emit_SLL(buf, dst, 0, value);
          case S390_ALU_RSH:  return s390_emit_SRL(buf, dst, 0, value);
          case S390_ALU_RSHA: return s390_emit_SRA(buf, dst, 0, value);
+         case S390_ALU_ILIH: ; /* avoid GCC warning */
          }
          goto fail;
 
@@ -9052,6 +9108,7 @@ s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
          case S390_ALU_LSH:  return s390_emit_SLLG(buf, dst, dst, 0, DISP20(value));
          case S390_ALU_RSH:  return s390_emit_SRLG(buf, dst, dst, 0, DISP20(value));
          case S390_ALU_RSHA: return s390_emit_SRAG(buf, dst, dst, 0, DISP20(value));
+         case S390_ALU_ILIH: ; /* avoid GCC warning */
          }
          goto fail;
       }
index c8ec665377f9025a1ef9769f541521214bcc7542..3f6473e10b0680e037e2ea39ac2802702144da6c 100644 (file)
@@ -178,6 +178,8 @@ typedef enum {
    S390_ALU_AND,
    S390_ALU_OR,
    S390_ALU_XOR,
+   S390_ALU_ILIH,  /* insert low half of 2nd operand into high half of 1st
+                      operand */
    S390_ALU_LSH,
    S390_ALU_RSH,
    S390_ALU_RSHA   /* arithmetic */
index 6d34ca5d63cd67f5de9f40639134573036ed1caf..ec042fb1171ed563734e1b5c93bc289042d7fafe 100644 (file)
@@ -1423,13 +1423,9 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
          h1   = s390_isel_int_expr(env, arg1);   /* Process 1st operand */
          h2   = s390_isel_int_expr(env, arg2);   /* Process 2nd operand */
 
-         addInstr(env, s390_insn_move(arg_size, res, h1));
-         value = s390_opnd_imm(arg_size * 8);
-         addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
-         value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
-         addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
-         opnd = s390_opnd_reg(h2);
-         addInstr(env, s390_insn_alu(size, S390_ALU_OR,  res, opnd));
+         addInstr(env, s390_insn_move(arg_size, res, h2));
+         opnd = s390_opnd_reg(h1);
+         addInstr(env, s390_insn_alu(size, S390_ALU_ILIH, res, opnd));
          return res;
       }