]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
riscv64: Fix IR generation for shift operations (BZ 509157)
authorFlorian Krohm <flo2030@eich-krohm.de>
Tue, 30 Sep 2025 20:14:24 +0000 (20:14 +0000)
committerFlorian Krohm <flo2030@eich-krohm.de>
Tue, 30 Sep 2025 20:14:24 +0000 (20:14 +0000)
For SLL, SRL, and SRA the shift amount is 6 bits wide - not 8 bits.
For SLLW, SRLW, and SRAW the shift amount is 5 bits wide - not 8 bits.

Patch for IR generation by Christoph Jung (christoph.j27@googlemail.com).

Also clarify semantics of bitwise shift operators in libvex_ir.h

Fixes https://bugs.kde.org/show_bug.cgi?id=509157

VEX/priv/guest_riscv64_toIR.c
VEX/pub/libvex_ir.h

index 59297acd15e5ccd4ff69e5416acf37d9e4054456..c90444ef1d0c5e52b0f746f6bf04c2cd2574c4e3 100644 (file)
@@ -1550,7 +1550,8 @@ static Bool dis_RV64I(/*MB_OUT*/ DisResult* dres,
                break;
             case 0b001:
                expr = binop(Iop_Shl64, getIReg64(rs1),
-                            unop(Iop_64to8, getIReg64(rs2)));
+                            unop(Iop_64to8, binop(Iop_And64, mkU64(0b00111111),
+                                                  getIReg64(rs2))));
                break;
             case 0b010:
                expr = unop(Iop_1Uto64,
@@ -1565,7 +1566,8 @@ static Bool dis_RV64I(/*MB_OUT*/ DisResult* dres,
                break;
             case 0b101:
                expr = binop(is_base ? Iop_Shr64 : Iop_Sar64, getIReg64(rs1),
-                            unop(Iop_64to8, getIReg64(rs2)));
+                            unop(Iop_64to8, binop(Iop_And64, mkU64(0b00111111),
+                                                  getIReg64(rs2))));
                break;
             case 0b110:
                expr = binop(Iop_Or64, getIReg64(rs1), getIReg64(rs2));
@@ -1719,7 +1721,9 @@ static Bool dis_RV64I(/*MB_OUT*/ DisResult* dres,
       if (rd != 0)
          putIReg32(
             irsb, rd,
-            binop(Iop_Shl32, getIReg32(rs1), unop(Iop_64to8, getIReg64(rs2))));
+            binop(Iop_Shl32, getIReg32(rs1),
+                  unop(Iop_64to8, binop(Iop_And64, mkU64(0b00011111),
+                                        getIReg64(rs2)))));
       DIP("sllw %s, %s, %s\n", nameIReg(rd), nameIReg(rs1), nameIReg(rs2));
       return True;
    }
@@ -1734,7 +1738,8 @@ static Bool dis_RV64I(/*MB_OUT*/ DisResult* dres,
       if (rd != 0)
          putIReg32(irsb, rd,
                    binop(is_log ? Iop_Shr32 : Iop_Sar32, getIReg32(rs1),
-                         unop(Iop_64to8, getIReg64(rs2))));
+                         unop(Iop_64to8, binop(Iop_And64, mkU64(0b00011111),
+                                               getIReg64(rs2)))));
       DIP("%s %s, %s, %s\n", is_log ? "srlw" : "sraw", nameIReg(rd),
           nameIReg(rs1), nameIReg(rs2));
       return True;
index 8c68fab4413807ece4710ded9502ea1f1910b450..7cb9c6b0f846b360ac622f1922ed5b14fba5957a 100644 (file)
@@ -434,6 +434,18 @@ typedef
       Iop_Or8,   Iop_Or16,   Iop_Or32,   Iop_Or64,
       Iop_And8,  Iop_And16,  Iop_And32,  Iop_And64,
       Iop_Xor8,  Iop_Xor16,  Iop_Xor32,  Iop_Xor64,
+      /* Bitwise shift ops
+         Semantics as per C standard:
+         If the value of the right operand is negative or is greater
+         than or equal to the width of the left operand, the behaviour is
+         undefined.
+         For Shl: The result of E1 << E2 is E1 left-shifted E2 bit positions.
+         Vacated bits are filled with zeroes.
+         For Shr: The result of E1 >> E2 is E1 right-shifted E2 bit positions.
+         Vacated bits are filled with zeroes.
+         For Sar: The result of E1 >> E2 is E1 right-shifted E2 bit positions.
+         Vacated bits are filled with the most significant bit of E1 prior
+         to shifting. */
       Iop_Shl8,  Iop_Shl16,  Iop_Shl32,  Iop_Shl64,
       Iop_Shr8,  Iop_Shr16,  Iop_Shr32,  Iop_Shr64,
       Iop_Sar8,  Iop_Sar16,  Iop_Sar32,  Iop_Sar64,