Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable BigInt for binaryen.js #7167

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ full changeset diff at the end of each section.
Current Trunk
-------------

- Binaryen.js now builds with BigInt support. The i64.const and f64.const_bits
functions now take BigInt parameters rather than pairs of numbers.

v121
----

Expand Down
17 changes: 3 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -326,20 +326,9 @@ else()
endif()

if(EMSCRIPTEN)
# Note: to debug with DWARF you will usually want to enable BIGINT support, as
# that helps avoid running Binaryen on the wasm after link. Binaryen's DWARF
# rewriting has known limitations, so avoiding it during link is recommended
# where possible (like local debugging).
#
# Note that this is debug info for Binaryen itself, that is, when you are
# debugging Binaryen source code. This flag has no impact on what Binaryen
# does when run on wasm files.
option(ENABLE_BIGINT "Enable wasm BigInt support" OFF)
if(ENABLE_BIGINT)
add_link_flag("-sWASM_BIGINT")
else()
add_link_flag("-sWASM_BIGINT=0")
endif()
# This is now on by default in Emscripten, but set it explicitly to continue
# building correctly on older Emscriptens.
add_link_flag("-sWASM_BIGINT")

if("${CMAKE_BUILD_TYPE}" MATCHES "Release")
# Extra check that cmake has set -O3 in its release flags.
Expand Down
8 changes: 4 additions & 4 deletions src/js/binaryen.js-post.js
Original file line number Diff line number Diff line change
Expand Up @@ -1049,10 +1049,10 @@ function wrapModule(module, self = {}) {
'store32'(offset, align, ptr, value, name) {
return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64'], strToStack(name));
},
'const'(x, y) {
'const'(x) {
return preserveStack(() => {
const tempLiteral = stackAlloc(sizeOfLiteral);
Module['_BinaryenLiteralInt64'](tempLiteral, x, y);
Module['_BinaryenLiteralInt64'](tempLiteral, BigInt(x));
Copy link
Member

@kripken kripken Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about making this backwards compatible? We could support (i32, undefined), (i32, i32), and (BigInt, undefined) with this code:

        // Convert to a BigInt. We support (x, undefined) where x is either a
        // BigInt or not, and also (x, y) where neither is a BigInt and y is the
        // higher bits.
        if (typeof x !== 'bigint') {
          x = BigInt(x || 0) | (BigInt(y || 0) << 32n);
        }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small code size cost seems reasonable to me here, personally. And it is nice to write binaryen.i64.const(42) and not need to remember 42n each time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

binaryen.i64.const(42) already works because of the explicit BigInt(x) conversion here. Except for compatibility, I don't think there's much benefit to supporting the two-argument version. How much do we value compatibility here? Would we have a deprecation plan, or would we support the two-argument version indefinitely?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think compatibility makes sense: there are users that are creating i64s with two arguments, and I don't see a strong reason to break them, given the burden on supporting the old format is minimal.

return Module['_BinaryenConst'](module, tempLiteral);
});
},
Expand Down Expand Up @@ -1438,10 +1438,10 @@ function wrapModule(module, self = {}) {
return Module['_BinaryenConst'](module, tempLiteral);
});
},
'const_bits'(x, y) {
'const_bits'(x) {
return preserveStack(() => {
const tempLiteral = stackAlloc(sizeOfLiteral);
Module['_BinaryenLiteralFloat64Bits'](tempLiteral, x, y);
Module['_BinaryenLiteralFloat64Bits'](tempLiteral, BigInt(x));
return Module['_BinaryenConst'](module, tempLiteral);
});
},
Expand Down
62 changes: 31 additions & 31 deletions test/binaryen.js/kitchen-sink.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ function makeFloat32(x) {
return module.f32.const(x);
}

function makeInt64(l, h) {
return module.i64.const(l, h);
function makeInt64(x) {
return module.i64.const(x);
}

function makeFloat64(x) {
Expand Down Expand Up @@ -214,7 +214,7 @@ function test_core() {
constF32 = module.f32.const(3.14),
constF64 = module.f64.const(2.1828),
constF32Bits = module.f32.const_bits(0xffff1234),
constF64Bits = module.f64.const_bits(0x5678abcd, 0xffff1234);
constF64Bits = module.f64.const_bits(0xffff12345678ABCDn)

var iIfF = binaryen.createType([binaryen.i32, binaryen.i64, binaryen.f32, binaryen.f64])

Expand All @@ -229,7 +229,7 @@ function test_core() {
var valueList = [
// Unary
module.i32.clz(module.i32.const(-10)),
module.i64.ctz(module.i64.const(-22, -1)),
module.i64.ctz(module.i64.const(295147905179352825834n)),
module.i32.popcnt(module.i32.const(-10)),
module.f32.neg(module.f32.const(-33.612)),
module.f64.abs(module.f64.const(-9005.841)),
Expand All @@ -241,7 +241,7 @@ function test_core() {
module.i32.eqz(module.i32.const(-10)),
module.i64.extend_s(module.i32.const(-10)),
module.i64.extend_u(module.i32.const(-10)),
module.i32.wrap(module.i64.const(-22, -1)),
module.i32.wrap(module.i64.const(295147905179352825834n)),
module.i32.trunc_s.f32(module.f32.const(-33.612)),
module.i64.trunc_s.f32(module.f32.const(-33.612)),
module.i32.trunc_u.f32(module.f32.const(-33.612)),
Expand All @@ -264,18 +264,18 @@ function test_core() {
module.f64.convert_s.i32(module.i32.const(-10)),
module.f32.convert_u.i32(module.i32.const(-10)),
module.f64.convert_u.i32(module.i32.const(-10)),
module.f32.convert_s.i64(module.i64.const(-22, -1)),
module.f64.convert_s.i64(module.i64.const(-22, -1)),
module.f32.convert_u.i64(module.i64.const(-22, -1)),
module.f64.convert_u.i64(module.i64.const(-22, -1)),
module.f32.convert_s.i64(module.i64.const(295147905179352825834n)),
module.f64.convert_s.i64(module.i64.const(295147905179352825834n)),
module.f32.convert_u.i64(module.i64.const(295147905179352825834n)),
module.f64.convert_u.i64(module.i64.const(295147905179352825834n)),
module.f64.promote(module.f32.const(-33.612)),
module.f32.demote(module.f64.const(-9005.841)),
module.f32.reinterpret(module.i32.const(-10)),
module.f64.reinterpret(module.i64.const(-22, -1)),
module.f64.reinterpret(module.i64.const(295147905179352825834n)),
module.i8x16.splat(module.i32.const(42)),
module.i16x8.splat(module.i32.const(42)),
module.i32x4.splat(module.i32.const(42)),
module.i64x2.splat(module.i64.const(123, 456)),
module.i64x2.splat(module.i64.const(1958505087099n)),
module.f32x4.splat(module.f32.const(42.0)),
module.f64x2.splat(module.f64.const(42.0)),
module.v128.not(module.v128.const(v128_bytes)),
Expand Down Expand Up @@ -333,31 +333,31 @@ function test_core() {
module.i32.add(module.i32.const(-10), module.i32.const(-11)),
module.f64.sub(module.f64.const(-9005.841), module.f64.const(-9007.333)),
module.i32.div_s(module.i32.const(-10), module.i32.const(-11)),
module.i64.div_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.rem_s(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.div_u(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i64.rem_s(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i32.rem_u(module.i32.const(-10), module.i32.const(-11)),
module.i32.and(module.i32.const(-10), module.i32.const(-11)),
module.i64.or(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.or(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i32.xor(module.i32.const(-10), module.i32.const(-11)),
module.i64.shl(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.shr_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.shl(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i64.shr_u(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i32.shr_s(module.i32.const(-10), module.i32.const(-11)),
module.i32.rotl(module.i32.const(-10), module.i32.const(-11)),
module.i64.rotr(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.rotr(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.f32.div(module.f32.const(-33.612), module.f32.const(-62.5)),
module.f64.copysign(module.f64.const(-9005.841), module.f64.const(-9007.333)),
module.f32.min(module.f32.const(-33.612), module.f32.const(-62.5)),
module.f64.max(module.f64.const(-9005.841), module.f64.const(-9007.333)),
module.i32.eq(module.i32.const(-10), module.i32.const(-11)),
module.f32.ne(module.f32.const(-33.612), module.f32.const(-62.5)),
module.i32.lt_s(module.i32.const(-10), module.i32.const(-11)),
module.i64.lt_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.le_s(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.lt_u(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i64.le_s(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i32.le_u(module.i32.const(-10), module.i32.const(-11)),
module.i64.gt_s(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.gt_s(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.i32.gt_u(module.i32.const(-10), module.i32.const(-11)),
module.i32.ge_s(module.i32.const(-10), module.i32.const(-11)),
module.i64.ge_u(module.i64.const(-22, 0), module.i64.const(-23, 0)),
module.i64.ge_u(module.i64.const(4294967274n), module.i64.const(4294967273n)),
module.f32.lt(module.f32.const(-33.612), module.f32.const(-62.5)),
module.f64.le(module.f64.const(-9005.841), module.f64.const(-9007.333)),
module.f64.gt(module.f64.const(-9005.841), module.f64.const(-9007.333)),
Expand Down Expand Up @@ -502,7 +502,7 @@ function test_core() {
module.i16x8.replace_lane(module.v128.const(v128_bytes), 1, module.i32.const(42)),
module.i8x16.replace_lane(module.v128.const(v128_bytes), 1, module.i32.const(42)),
module.i32x4.replace_lane(module.v128.const(v128_bytes), 1, module.i32.const(42)),
module.i64x2.replace_lane(module.v128.const(v128_bytes), 1, module.i64.const(42, 43)),
module.i64x2.replace_lane(module.v128.const(v128_bytes), 1, module.i64.const(184683593770n)),
module.f32x4.replace_lane(module.v128.const(v128_bytes), 1, module.f32.const(42)),
module.f64x2.replace_lane(module.v128.const(v128_bytes), 1, module.f64.const(42)),
// SIMD shift
Expand Down Expand Up @@ -569,15 +569,15 @@ function test_core() {
module.switch([ "the-value" ], "the-value", temp8, temp9),
module.switch([ "the-nothing" ], "the-nothing", makeInt32(2)),
module.i32.eqz( // check the output type of the call node
module.call("kitchen()sinker", [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], binaryen.i32)
module.call("kitchen()sinker", [ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ], binaryen.i32)
),
module.i32.eqz( // check the output type of the call node
module.i32.trunc_s.f32(
module.call("an-imported", [ makeInt32(13), makeFloat64(3.7) ], binaryen.f32)
)
),
module.i32.eqz( // check the output type of the call node
module.call_indirect("t0", makeInt32(2449), [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], iIfF, binaryen.i32)
module.call_indirect("t0", makeInt32(2449), [ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ], iIfF, binaryen.i32)
),
module.drop(module.local.get(0, binaryen.i32)),
module.local.set(0, makeInt32(101)),
Expand All @@ -591,8 +591,8 @@ function test_core() {
module.select(temp10, temp11, temp12),
module.return(makeInt32(1337)),
// Tail Call
module.return_call("kitchen()sinker", [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], binaryen.i32),
module.return_call_indirect("t0", makeInt32(2449), [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], iIfF, binaryen.i32),
module.return_call("kitchen()sinker", [ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ], binaryen.i32),
module.return_call_indirect("t0", makeInt32(2449), [ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ], iIfF, binaryen.i32),

// Reference types
module.ref.is_null(module.ref.null(binaryen.externref)),
Expand Down Expand Up @@ -636,11 +636,11 @@ function test_core() {

// Tuples
module.tuple.make(
[ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ]
[ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ]
),
module.tuple.extract(
module.tuple.make(
[ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ]
[ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ]
), 2
),

Expand Down Expand Up @@ -695,11 +695,11 @@ function test_core() {
}

console.log("getExpressionInfo(i32.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.i32.const(5))));
console.log("getExpressionInfo(i64.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.i64.const(6, 7))));
console.log("getExpressionInfo(i64.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.i64.const(30064771078n))));
console.log("getExpressionInfo(f32.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.f32.const(8.5))));
console.log("getExpressionInfo(f64.const)=" + JSON.stringify(binaryen.getExpressionInfo(module.f64.const(9.5))));
var elements = binaryen.getExpressionInfo(
module.tuple.make([ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ])
module.tuple.make([ makeInt32(13), makeInt64(37), makeFloat32(1.3), makeFloat64(3.7) ])
).operands;
for (var i = 0; i < elements.length; i++) {
console.log("getExpressionInfo(tuple[" + i + "])=" + JSON.stringify(binaryen.getExpressionInfo(elements[i])));
Expand Down Expand Up @@ -1018,7 +1018,7 @@ function test_nonvalid() {
module = new binaryen.Module();

var func = module.addFunction("func", binaryen.none, binaryen.none, [ binaryen.i32 ],
module.local.set(0, makeInt64(1234, 0)) // wrong type!
module.local.set(0, makeInt64(1234)) // wrong type!
);

console.log(module.emitText());
Expand Down
4 changes: 2 additions & 2 deletions test/binaryen.js/validation_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
)
])
);
mod.addExport("test", func);
mod.addExport("test", "test");
console.log(mod.validate())
})();

Expand All @@ -20,6 +20,6 @@
)
])
);
mod.addFunctionExport("test", "test", func);
mod.addFunctionExport("test", "test");
console.log(mod.validate())
})();
Loading