]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Simplify single multiplications
authorAndreas Arnez <arnez@linux.ibm.com>
Fri, 5 Dec 2025 17:01:22 +0000 (18:01 +0100)
committerAndreas Arnez <arnez@linux.ibm.com>
Thu, 11 Dec 2025 12:41:30 +0000 (13:41 +0100)
So far the single-multiplication instructions are implemented by taking
the low half of a widening multiply.  This pattern is then recognized by
the instruction selector, which combines it to a single multiplication
again.

This is unnecessarily complicated, since single-multiply operations can be
expressed directly by Iop_Mul32 and Iop_Mul64 instead.  So do this,
simplifying the code generation.

Also, since Iop_Mul32 and Iop_Mul64 haven't really been used before, the
instruction selector generates sub-optimal code for them.  Fix that.

VEX/priv/guest_s390_toIR.c
VEX/priv/host_s390_isel.c

index 8f42c844d3c90beba55e30b4340ed3f844ad7ae0..9e850b78ffaab4721b020e9d293bc1a98114f9da 100644 (file)
@@ -9015,14 +9015,7 @@ s390_irgen_MLG(UChar r1, IRTemp op2addr)
 static const HChar *
 s390_irgen_MSR(UChar r1, UChar r2)
 {
-   IRTemp op1 = newTemp(Ity_I32);
-   IRTemp op2 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I64);
-
-   assign(op1, get_gpr_w1(r1));
-   assign(op2, get_gpr_w1(r2));
-   assign(result, binop(Iop_MullS32, mkexpr(op1), mkexpr(op2)));
-   put_gpr_w1(r1, unop(Iop_64to32, mkexpr(result)));
+   put_gpr_w1(r1, binop(Iop_Mul32, get_gpr_w1(r1), get_gpr_w1(r2)));
 
    return "msr";
 }
@@ -9030,14 +9023,7 @@ s390_irgen_MSR(UChar r1, UChar r2)
 static const HChar *
 s390_irgen_MSGR(UChar r1, UChar r2)
 {
-   IRTemp op1 = newTemp(Ity_I64);
-   IRTemp op2 = newTemp(Ity_I64);
-   IRTemp result = newTemp(Ity_I128);
-
-   assign(op1, get_gpr_dw0(r1));
-   assign(op2, get_gpr_dw0(r2));
-   assign(result, binop(Iop_MullS64, mkexpr(op1), mkexpr(op2)));
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   put_gpr_dw0(r1, binop(Iop_Mul64, get_gpr_dw0(r1), get_gpr_dw0(r2)));
 
    return "msgr";
 }
@@ -9045,15 +9031,8 @@ s390_irgen_MSGR(UChar r1, UChar r2)
 static const HChar *
 s390_irgen_MSGFR(UChar r1, UChar r2)
 {
-   IRTemp op1 = newTemp(Ity_I64);
-   IRTemp op2 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I128);
-
-   assign(op1, get_gpr_dw0(r1));
-   assign(op2, get_gpr_w1(r2));
-   assign(result, binop(Iop_MullS64, mkexpr(op1), unop(Iop_32Sto64, mkexpr(op2))
-          ));
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   put_gpr_dw0(
+      r1, binop(Iop_Mul64, get_gpr_dw0(r1), unop(Iop_32Sto64, get_gpr_w1(r2))));
 
    return "msgfr";
 }
@@ -9061,14 +9040,8 @@ s390_irgen_MSGFR(UChar r1, UChar r2)
 static const HChar *
 s390_irgen_MS(UChar r1, IRTemp op2addr)
 {
-   IRTemp op1 = newTemp(Ity_I32);
-   IRTemp op2 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I64);
-
-   assign(op1, get_gpr_w1(r1));
-   assign(op2, load(Ity_I32, mkexpr(op2addr)));
-   assign(result, binop(Iop_MullS32, mkexpr(op1), mkexpr(op2)));
-   put_gpr_w1(r1, unop(Iop_64to32, mkexpr(result)));
+   put_gpr_w1(r1,
+              binop(Iop_Mul32, get_gpr_w1(r1), load(Ity_I32, mkexpr(op2addr))));
 
    return "ms";
 }
@@ -9078,13 +9051,11 @@ s390_irgen_MSC(UChar r1, IRTemp op2addr)
 {
    IRTemp op1 = newTemp(Ity_I32);
    IRTemp op2 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I64);
 
    assign(op1, get_gpr_w1(r1));
    assign(op2, load(Ity_I32, mkexpr(op2addr)));
-   assign(result, binop(Iop_MullS32, mkexpr(op1), mkexpr(op2)));
    s390_cc_thunk_putSS(S390_CC_OP_MUL_32, op1, op2);
-   put_gpr_w1(r1, unop(Iop_64to32, mkexpr(result)));
+   put_gpr_w1(r1, binop(Iop_Mul32, mkexpr(op1), mkexpr(op2)));
 
    return "msc";
 }
@@ -9094,13 +9065,11 @@ s390_irgen_MSRKC(UChar r3, UChar r1, UChar r2)
 {
    IRTemp op2 = newTemp(Ity_I32);
    IRTemp op3 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I64);
 
    assign(op2, get_gpr_w1(r2));
    assign(op3, get_gpr_w1(r3));
-   assign(result, binop(Iop_MullS32, mkexpr(op2), mkexpr(op3)));
    s390_cc_thunk_putSS(S390_CC_OP_MUL_32, op2, op3);
-   put_gpr_w1(r1, unop(Iop_64to32, mkexpr(result)));
+   put_gpr_w1(r1, binop(Iop_Mul32, mkexpr(op2), mkexpr(op3)));
 
    return "msrkc";
 }
@@ -9108,14 +9077,8 @@ s390_irgen_MSRKC(UChar r3, UChar r1, UChar r2)
 static const HChar *
 s390_irgen_MSY(UChar r1, IRTemp op2addr)
 {
-   IRTemp op1 = newTemp(Ity_I32);
-   IRTemp op2 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I64);
-
-   assign(op1, get_gpr_w1(r1));
-   assign(op2, load(Ity_I32, mkexpr(op2addr)));
-   assign(result, binop(Iop_MullS32, mkexpr(op1), mkexpr(op2)));
-   put_gpr_w1(r1, unop(Iop_64to32, mkexpr(result)));
+   put_gpr_w1(r1,
+              binop(Iop_Mul32, get_gpr_w1(r1), load(Ity_I32, mkexpr(op2addr))));
 
    return "msy";
 }
@@ -9123,14 +9086,8 @@ s390_irgen_MSY(UChar r1, IRTemp op2addr)
 static const HChar *
 s390_irgen_MSG(UChar r1, IRTemp op2addr)
 {
-   IRTemp op1 = newTemp(Ity_I64);
-   IRTemp op2 = newTemp(Ity_I64);
-   IRTemp result = newTemp(Ity_I128);
-
-   assign(op1, get_gpr_dw0(r1));
-   assign(op2, load(Ity_I64, mkexpr(op2addr)));
-   assign(result, binop(Iop_MullS64, mkexpr(op1), mkexpr(op2)));
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   put_gpr_dw0(r1,
+              binop(Iop_Mul64, get_gpr_dw0(r1), load(Ity_I64, mkexpr(op2addr))));
 
    return "msg";
 }
@@ -9140,13 +9097,11 @@ s390_irgen_MSGC(UChar r1, IRTemp op2addr)
 {
    IRTemp op1 = newTemp(Ity_I64);
    IRTemp op2 = newTemp(Ity_I64);
-   IRTemp result = newTemp(Ity_I128);
 
    assign(op1, get_gpr_dw0(r1));
    assign(op2, load(Ity_I64, mkexpr(op2addr)));
-   assign(result, binop(Iop_MullS64, mkexpr(op1), mkexpr(op2)));
    s390_cc_thunk_putSS(S390_CC_OP_MUL_64, op1, op2);
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   put_gpr_dw0(r1, binop(Iop_Mul64, mkexpr(op1), mkexpr(op2)));
 
    return "msgc";
 }
@@ -9154,15 +9109,8 @@ s390_irgen_MSGC(UChar r1, IRTemp op2addr)
 static const HChar *
 s390_irgen_MSGF(UChar r1, IRTemp op2addr)
 {
-   IRTemp op1 = newTemp(Ity_I64);
-   IRTemp op2 = newTemp(Ity_I32);
-   IRTemp result = newTemp(Ity_I128);
-
-   assign(op1, get_gpr_dw0(r1));
-   assign(op2, load(Ity_I32, mkexpr(op2addr)));
-   assign(result, binop(Iop_MullS64, mkexpr(op1), unop(Iop_32Sto64, mkexpr(op2))
-          ));
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   put_gpr_dw0(r1, binop(Iop_Mul64, get_gpr_dw0(r1),
+                         unop(Iop_32Sto64, load(Ity_I32, mkexpr(op2addr)))));
 
    return "msgf";
 }
@@ -9170,14 +9118,7 @@ s390_irgen_MSGF(UChar r1, IRTemp op2addr)
 static const HChar *
 s390_irgen_MSFI(UChar r1, UInt i2)
 {
-   IRTemp op1 = newTemp(Ity_I32);
-   Int op2;
-   IRTemp result = newTemp(Ity_I64);
-
-   assign(op1, get_gpr_w1(r1));
-   op2 = (Int)i2;
-   assign(result, binop(Iop_MullS32, mkexpr(op1), mkU32((UInt)op2)));
-   put_gpr_w1(r1, unop(Iop_64to32, mkexpr(result)));
+   put_gpr_w1(r1, binop(Iop_Mul32, get_gpr_w1(r1), mkU32(i2)));
 
    return "msfi";
 }
@@ -9185,15 +9126,8 @@ s390_irgen_MSFI(UChar r1, UInt i2)
 static const HChar *
 s390_irgen_MSGFI(UChar r1, UInt i2)
 {
-   IRTemp op1 = newTemp(Ity_I64);
-   Int op2;
-   IRTemp result = newTemp(Ity_I128);
-
-   assign(op1, get_gpr_dw0(r1));
-   op2 = (Int)i2;
-   assign(result, binop(Iop_MullS64, mkexpr(op1), unop(Iop_32Sto64, mkU32((UInt)
-          op2))));
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   ULong op2 = (ULong)i2 - (((ULong)i2 & (1 << 31)) << 1);
+   put_gpr_dw0(r1, binop(Iop_Mul64, get_gpr_dw0(r1), mkU64(op2)));
 
    return "msgfi";
 }
@@ -9203,13 +9137,11 @@ s390_irgen_MSGRKC(UChar r3, UChar r1, UChar r2)
 {
    IRTemp op2 = newTemp(Ity_I64);
    IRTemp op3 = newTemp(Ity_I64);
-   IRTemp result = newTemp(Ity_I128);
 
    assign(op2, get_gpr_dw0(r2));
    assign(op3, get_gpr_dw0(r3));
-   assign(result, binop(Iop_MullS64, mkexpr(op2), mkexpr(op3)));
    s390_cc_thunk_putSS(S390_CC_OP_MUL_64, op2, op3);
-   put_gpr_dw0(r1, unop(Iop_128to64, mkexpr(result)));
+   put_gpr_dw0(r1, binop(Iop_Mul64, mkexpr(op2), mkexpr(op3)));
 
    return "msgrkc";
 }
index 9cb9b65d3b5994459d6d14b28b6b0ec01e8499a6..ffe8a82a2a6f0a92083f9ba2e6928f2610ea7f40 100644 (file)
@@ -1277,13 +1277,21 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
          goto do_multiply;
 
       do_multiply: {
-            HReg r10, r11;
-            UInt arg_size = is_single_multiply ? size : size / 2;
-
             order_commutative_operands(arg1, arg2);
 
             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
+            res  = newVRegI(env);
+
+            if (is_single_multiply) {
+               /* No register pair needed */
+               addInstr(env, s390_insn_move(size, res, h1));
+               addInstr(env, s390_insn_alu(size, S390_ALU_MUL, res, op2));
+               return res;
+            }
+
+            HReg r10, r11;
+            UInt arg_size = size / 2;
 
             /* We use non-virtual registers r10 and r11 as pair */
             r10  = make_gpr(10);
@@ -1295,7 +1303,6 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
             /* Multiply */
             addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
 
-            res  = newVRegI(env);
             if (arg_size == 1 || arg_size == 2) {
                /* For 8-bit and 16-bit multiplication the result is in
                   r11[32:63] */
@@ -1303,12 +1310,6 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
                return res;
             }
 
-            /* For Iop_Mul64 the result is in r11[0:63] */
-            if (expr->Iex.Binop.op == Iop_Mul64) {
-               addInstr(env, s390_insn_move(size, res, r11));
-               return res;
-            }
-
             /* The result is in registers r10 and r11. Combine them into a SIZE-bit
                value into the destination register. */
             addInstr(env, s390_insn_move(arg_size, res, r10));