]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Exploit instructions for bitwise NAND and NOR 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)
Newer z/Architecture machines have the instructions NORK and NOGRK for
calculating bit-wise NOR, as well as NNRK and NNGRK for bitwise NAND.
Exploit those when applicable.

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

index 0f04db5bf8cf03954eca8c2a7b705390a7c91e82..691978d20217294860e2736bd72ac141eba06b65 100644 (file)
@@ -4210,6 +4210,30 @@ s390_emit_OCGRK(UChar *p, UChar r1, UChar r2, UChar r3)
    return emit_RRF6(p, 0xb9650000, r1, r2, r3);
 }
 
+static UChar *
+s390_emit_NNRK(UChar *p, UChar r1, UChar r2, UChar r3)
+{
+   return emit_RRF6(p, 0xb9740000, r1, r2, r3);
+}
+
+static UChar *
+s390_emit_NNGRK(UChar *p, UChar r1, UChar r2, UChar r3)
+{
+   return emit_RRF6(p, 0xb9640000, r1, r2, r3);
+}
+
+static UChar *
+s390_emit_NORK(UChar *p, UChar r1, UChar r2, UChar r3)
+{
+   return emit_RRF6(p, 0xb9760000, r1, r2, r3);
+}
+
+static UChar *
+s390_emit_NOGRK(UChar *p, UChar r1, UChar r2, UChar r3)
+{
+   return emit_RRF6(p, 0xb9660000, r1, r2, r3);
+}
+
 
 /* Provide a symbolic name for register "R0" */
 #define R0 0
@@ -6274,6 +6298,8 @@ s390_insn_as_string(const s390_insn *insn)
       switch (insn->variant.alu3.tag) {
       case S390_ALU3_ANDC: op = "v-andc"; break;
       case S390_ALU3_ORC:  op = "v-orc";  break;
+      case S390_ALU3_NAND: op = "v-nand"; break;
+      case S390_ALU3_NOR:  op = "v-nor";  break;
       default: goto fail;
       }
       s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.alu3.dst,
@@ -7658,6 +7684,12 @@ s390_insn_alu3_emit(UChar *buf, const s390_insn *insn)
    case S390_ALU3_ORC:
       return insn->size == 4 ? s390_emit_OCRK(buf, dst, op1, op2)
                              : s390_emit_OCGRK(buf, dst, op1, op2);
+   case S390_ALU3_NAND:
+      return insn->size == 4 ? s390_emit_NNRK(buf, dst, op1, op2)
+                             : s390_emit_NNGRK(buf, dst, op1, op2);
+   case S390_ALU3_NOR:
+      return insn->size == 4 ? s390_emit_NORK(buf, dst, op1, op2)
+                             : s390_emit_NOGRK(buf, dst, op1, op2);
    default:
       goto fail;
    }
index e4a4f9be4fce92109898371c51e95dbb9dcc45a1..2a5d7a4f73986ef7409371a10270b15a2d44f02e 100644 (file)
@@ -189,6 +189,8 @@ typedef enum {
 typedef enum {
    S390_ALU3_ANDC, /* and with complement */
    S390_ALU3_ORC,  /* or with complement */
+   S390_ALU3_NAND,
+   S390_ALU3_NOR,
 } s390_alu3_t;
 
 /* The kind of unary integer operations */
index d7b657de6235821445fb8f805a37b9e2bcb152ad..04a2e053eb0beda04172222be5952dac8c7120d9 100644 (file)
@@ -1864,8 +1864,6 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
          return dst;
       }
 
-      /* Regular processing */
-
       if (unop == Iop_128to64) {
          HReg dst_hi, dst_lo;
 
@@ -1905,6 +1903,38 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
          return dst;
       }
 
+      /* NAND or NOR */
+      if ((env->hwcaps & VEX_HWCAPS_S390X_MI3) && is_IRExpr_Not(expr) &&
+          arg->tag == Iex_Binop) {
+         s390_alu3_t bitop;
+
+         switch (binop) {
+         case Iop_And8:
+         case Iop_And16:
+         case Iop_And32:
+         case Iop_And64:
+            bitop = S390_ALU3_NAND;
+            goto do_nand_nor;
+         case Iop_Or8:
+         case Iop_Or16:
+         case Iop_Or32:
+         case Iop_Or64:
+            bitop = S390_ALU3_NOR;
+         do_nand_nor: {
+            HReg h2;
+            dst = newVRegI(env);
+            h1  = s390_isel_int_expr(env, arg->Iex.Binop.arg1);
+            h2  = s390_isel_int_expr(env, arg->Iex.Binop.arg2);
+            addInstr(env,
+                     s390_insn_alu3(size <= 4 ? 4 : 8, bitop, dst, h1, h2));
+            return dst;
+         }
+         default:;
+         }
+      }
+
+      /* Regular processing */
+
       dst  = newVRegI(env);     /* Result goes into a new register */
       opnd = s390_isel_int_expr_RMI(env, arg);     /* Process the operand */
 
@@ -1974,10 +2004,16 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
       case Iop_Not16:
       case Iop_Not32:
       case Iop_Not64:
-         /* XOR with ffff... */
-         mask.variant.imm = ~(ULong)0;
-         addInstr(env, s390_opnd_copy(size, dst, opnd));
-         insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
+         if ((env->hwcaps & VEX_HWCAPS_S390X_MI3) &&
+             opnd.tag == S390_OPND_REG) {
+            insn = s390_insn_alu3(size <= 4 ? 4 : 8, S390_ALU3_NOR, dst,
+                                  opnd.variant.reg, opnd.variant.reg);
+         } else {
+            /* XOR with ffff... */
+            addInstr(env, s390_opnd_copy(size, dst, opnd));
+            mask.variant.imm = ~(ULong)0;
+            insn             = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
+         }
          break;
 
       case Iop_Left8: