From: Florian Krohm Date: Tue, 30 Sep 2025 20:14:24 +0000 (+0000) Subject: riscv64: Fix IR generation for shift operations (BZ 509157) X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=97831bbbc208f3c574095770aff9b19e5a2c6aae;p=thirdparty%2Fvalgrind.git riscv64: Fix IR generation for shift operations (BZ 509157) 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 --- diff --git a/VEX/priv/guest_riscv64_toIR.c b/VEX/priv/guest_riscv64_toIR.c index 59297acd1..c90444ef1 100644 --- a/VEX/priv/guest_riscv64_toIR.c +++ b/VEX/priv/guest_riscv64_toIR.c @@ -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; diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 8c68fab44..7cb9c6b0f 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -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,