From fa8a149ed1b8541831be9454bb586c23a3e0455f Mon Sep 17 00:00:00 2001 From: Aakash Patel Date: Fri, 31 Jan 2025 10:12:22 -0800 Subject: [PATCH] JIT: Use ucvtf for unsigned right shift Summary: Unsigned right shift is supposed to convert back from an unsigned 32-bit integer, not a 2s complement int. Reviewed By: lavenzg Differential Revision: D68923851 fbshipit-source-id: cffe3746c850d7cb603a3670ea435ff564c84345 --- lib/VM/JIT/arm64/JitEmitter.cpp | 6 ++++- lib/VM/JIT/arm64/JitEmitter.h | 42 ++++++++++++++++++--------------- test/jit/binops.js | 8 +++++++ 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/lib/VM/JIT/arm64/JitEmitter.cpp b/lib/VM/JIT/arm64/JitEmitter.cpp index 86ee8699f1d..f3f14f7e17a 100644 --- a/lib/VM/JIT/arm64/JitEmitter.cpp +++ b/lib/VM/JIT/arm64/JitEmitter.cpp @@ -5192,6 +5192,7 @@ void Emitter::bitBinOp( FR frRes, FR frLeft, FR frRight, + bool unsignedRes, const char *name, SHLegacyValue (*slowCall)( SHRuntime *shr, @@ -5253,7 +5254,10 @@ void Emitter::bitBinOp( // Invoke the fast path, and move the result back as a 32 bit integer. fast(a, hwTempLGpX.a64GpX(), hwTempLGpX.a64GpX(), hwTempRGpX.a64GpX()); - a.scvtf(hwRes.a64VecD(), hwTempLGpX.a64GpX().w()); + if (unsignedRes) + a.ucvtf(hwRes.a64VecD(), hwTempLGpX.a64GpX().w()); + else + a.scvtf(hwRes.a64VecD(), hwTempLGpX.a64GpX().w()); a.bind(contLab); diff --git a/lib/VM/JIT/arm64/JitEmitter.h b/lib/VM/JIT/arm64/JitEmitter.h index e46825aee43..7cf22d7ff62 100644 --- a/lib/VM/JIT/arm64/JitEmitter.h +++ b/lib/VM/JIT/arm64/JitEmitter.h @@ -492,35 +492,38 @@ class Emitter { DECL_BINOP(divN, true, "divN", _sh_ljs_div_rjs, { as.fdiv(res, dl, dr); }) #undef DECL_BINOP -#define DECL_BIT_BINOP(methodName, commentStr, slowCall, a64body) \ - void methodName(FR rRes, FR rLeft, FR rRight) { \ - bitBinOp( \ - rRes, \ - rLeft, \ - rRight, \ - commentStr, \ - slowCall, \ - #slowCall, \ - [](a64::Assembler & a, \ - const a64::GpX &res, \ - const a64::GpX &dl, \ - const a64::GpX &dr) a64body); \ +#define DECL_BIT_BINOP(methodName, unsignedRes, commentStr, slowCall, a64body) \ + void methodName(FR rRes, FR rLeft, FR rRight) { \ + bitBinOp( \ + rRes, \ + rLeft, \ + rRight, \ + unsignedRes, \ + commentStr, \ + slowCall, \ + #slowCall, \ + [](a64::Assembler & a, \ + const a64::GpX &res, \ + const a64::GpX &dl, \ + const a64::GpX &dr) a64body); \ } - DECL_BIT_BINOP(bitAnd, "bit_and", _sh_ljs_bit_and_rjs, { + DECL_BIT_BINOP(bitAnd, false, "bit_and", _sh_ljs_bit_and_rjs, { a.and_(res, dl, dr); }) - DECL_BIT_BINOP(bitOr, "bit_or", _sh_ljs_bit_or_rjs, { a.orr(res, dl, dr); }) - DECL_BIT_BINOP(bitXor, "bit_xor", _sh_ljs_bit_xor_rjs, { + DECL_BIT_BINOP(bitOr, false, "bit_or", _sh_ljs_bit_or_rjs, { + a.orr(res, dl, dr); + }) + DECL_BIT_BINOP(bitXor, false, "bit_xor", _sh_ljs_bit_xor_rjs, { a.eor(res, dl, dr); }) - DECL_BIT_BINOP(lShift, "lshift", _sh_ljs_left_shift_rjs, { + DECL_BIT_BINOP(lShift, false, "lshift", _sh_ljs_left_shift_rjs, { a.lsl(res.w(), dl.w(), dr.w()); }) - DECL_BIT_BINOP(rShift, "rshift", _sh_ljs_right_shift_rjs, { + DECL_BIT_BINOP(rShift, false, "rshift", _sh_ljs_right_shift_rjs, { a.asr(res.w(), dl.w(), dr.w()); }) - DECL_BIT_BINOP(urShift, "rshiftu", _sh_ljs_unsigned_right_shift_rjs, { + DECL_BIT_BINOP(urShift, true, "rshiftu", _sh_ljs_unsigned_right_shift_rjs, { a.lsr(res.w(), dl.w(), dr.w()); }) @@ -1116,6 +1119,7 @@ class Emitter { FR frRes, FR frLeft, FR frRight, + bool unsignedRes, const char *name, SHLegacyValue (*slowCall)( SHRuntime *shr, diff --git a/test/jit/binops.js b/test/jit/binops.js index b3fbd023324..abe24c1d7a0 100644 --- a/test/jit/binops.js +++ b/test/jit/binops.js @@ -22,3 +22,11 @@ function addS(b) { print("addS", addS("B")); // CHECK-NEXT: addS aBc + +function ushr0(a) { + return a >>> 0; +} +print(ushr0(-2000000000)); +// CHECK-NEXT: 2294967296 +print(ushr0(3000000000)); +// CHECK-NEXT: 3000000000