Skip to content

Commit

Permalink
Cherry-pick 275011@main (3ee7e4f). https://bugs.webkit.org/show_bug.c…
Browse files Browse the repository at this point in the history
…gi?id=269729

    Emit logical right-shift for unsigned div in BBQ JIT
    https://bugs.webkit.org/show_bug.cgi?id=269729
    rdar://120840889

    Reviewed by Justin Michaud.

    Previously, the function BBQ::emitModOrDiv would unconditionally emit
    an arithmetic right-shift in cases where the lhs was a power of two.
    This produces the correct result when the sign bit is 0 (i.e. the lhs,
    interpreted as a signed 64-bit integer, is positive) but an incorrect
    one when the sign bit is 1: specifically, it would compute a signed
    division instead.
    By checking the sign of the division taking place and emitting a logical
    shift when the operation is unsigned, we get the correct result.

    * JSTests/wasm/stress/i64divu-sign-maintanance.js: Added.
    (async test):
    * Source/JavaScriptCore/wasm/WasmBBQJIT64.h:
    (JSC::Wasm::BBQJITImpl::BBQJIT::emitModOrDiv):

    Canonical link: https://commits.webkit.org/275011@main

Canonical link: https://commits.webkit.org/274313.42@webkitglib/2.44
  • Loading branch information
Achierius authored and aperezdc committed Mar 8, 2024
1 parent 717b4e0 commit 92508f1
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 4 deletions.
48 changes: 48 additions & 0 deletions JSTests/wasm/stress/unsigned-integer-division.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { instantiate } from "../wabt-wrapper.js";
import * as assert from "../assert.js";

// If we compute using a signed division, then the results of the long computation inside the `if`s below
// will be a large negative number rather than a large positive one, and the functions will return 1.
let wat = `
(module
(type (func (param f64) (result i32)))
(func (export "test64") (type 0) (local i64) (local i32)
(local.set 1 (i64.const -9999))
(if (i64.le_s (i64.clz (i64.add (local.get 1) (i64.const 1))) (i64.sub (i64.div_u (local.get 1) (i64.const 2)) (i64.const 2)))
(then (local.set 2 (i32.const 0)))
(else (local.set 2 (i32.const 1)))
)
(local.get 2)
)
(type (func (param f32) (result i32)))
(func (export "test32") (type 1) (local i32) (local i32)
(local.set 1 (i32.const -9999))
(if (i32.le_s (i32.clz (i32.add (local.get 1) (i32.const 1))) (i32.sub (i32.div_u (local.get 1) (i32.const 2)) (i32.const 2)))
(then (local.set 2 (i32.const 0)))
(else (local.set 2 (i32.const 1)))
)
(local.get 2)
)
)
`;

async function test() {
const instance = await instantiate(wat, {}, {});
const {test64, test32} = instance.exports;
for (let i = 0; i < 100; i++) {
assert.eq(test64(10.0), 0);
assert.eq(test32(10.0), 0);

assert.eq(test64(-10.0), 0);
assert.eq(test32(-10.0), 0);

assert.eq(test64(1028.0), 0);
assert.eq(test32(1028.0), 0);

assert.eq(test64(1234.0), 0);
assert.eq(test32(1234.0), 0);
}
}

assert.asyncTest(test());
17 changes: 13 additions & 4 deletions Source/JavaScriptCore/wasm/WasmBBQJIT64.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,19 @@ void BBQJIT::emitModOrDiv(Value& lhs, Location lhsLocation, Value& rhs, Location
lhsLocation = Location::fromGPR(wasmScratchGPR);
}

if constexpr (is32)
m_jit.rshift32(lhsLocation.asGPR(), m_jit.trustedImm32ForShift(Imm32(WTF::fastLog2(static_cast<unsigned>(divisor)))), resultLocation.asGPR());
else
m_jit.rshift64(lhsLocation.asGPR(), TrustedImm32(WTF::fastLog2(static_cast<uint64_t>(divisor))), resultLocation.asGPR());
// Emit the actual division instruction: arithmetic shift if signed,
// logical shift if unsigned
if constexpr (isSigned) {
if constexpr (is32)
m_jit.rshift32(lhsLocation.asGPR(), m_jit.trustedImm32ForShift(Imm32(WTF::fastLog2(static_cast<unsigned>(divisor)))), resultLocation.asGPR());
else
m_jit.rshift64(lhsLocation.asGPR(), TrustedImm32(WTF::fastLog2(static_cast<uint64_t>(divisor))), resultLocation.asGPR());
} else {
if constexpr (is32)
m_jit.urshift32(lhsLocation.asGPR(), m_jit.trustedImm32ForShift(Imm32(WTF::fastLog2(static_cast<unsigned>(divisor)))), resultLocation.asGPR());
else
m_jit.urshift64(lhsLocation.asGPR(), TrustedImm32(WTF::fastLog2(static_cast<uint64_t>(divisor))), resultLocation.asGPR());
}

return;
}
Expand Down

0 comments on commit 92508f1

Please sign in to comment.