diff options
Diffstat (limited to 'test/binaryen.js/kitchen-sink.js')
-rw-r--r-- | test/binaryen.js/kitchen-sink.js | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js new file mode 100644 index 000000000..773757ff0 --- /dev/null +++ b/test/binaryen.js/kitchen-sink.js @@ -0,0 +1,508 @@ + +// kitchen sink, tests the full API + +var module; + +// helpers + +function assert(x) { + if (!x) throw 'error!'; +} + +function makeInt32(x) { + return module.i32.const(x); +} + +function makeFloat32(x) { + return module.f32.const(x); +} + +function makeInt64(l, h) { + return module.i64.const(l, h); +} + +function makeFloat64(x) { + return module.f64.const(x); +} + +function makeSomething() { + return makeInt32(1337); +} + +function makeDroppedInt32(x) { + return module.drop(module.i32.const(x)); +} + +// tests + +function test_types() { + console.log("BinaryenNone: " + Binaryen.none); + console.log("BinaryenInt32: " + Binaryen.i32); + console.log("BinaryenInt64: " + Binaryen.i64); + console.log("BinaryenFloat32: " + Binaryen.f32); + console.log("BinaryenFloat64: " + Binaryen.f64); +} + +function test_core() { + + // Module creation + + module = new Binaryen.Module(); + + // Literals and consts + + var constI32 = module.i32.const(1), + constI64 = module.i64.const(2), + 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); + + var iiIfF = module.addFunctionType("iiIfF", Binaryen.i32, [ Binaryen.i32, Binaryen.i64, Binaryen.f32, Binaryen.f64 ]); + + var temp1 = makeInt32(1), temp2 = makeInt32(2), temp3 = makeInt32(3), + temp4 = makeInt32(4), temp5 = makeInt32(5), + temp6 = makeInt32(0), temp7 = makeInt32(1), + temp8 = makeInt32(0), temp9 = makeInt32(1), + temp10 = makeInt32(1), temp11 = makeInt32(3), temp12 = makeInt32(5), + temp13 = makeInt32(10), temp14 = makeInt32(11), + temp15 = makeInt32(110), temp16 = makeInt64(111); + + var valueList = [ + // Unary + module.i32.clz(module.i32.const(-10)), + module.i64.ctz(module.i64.const(-22, -1)), + module.i32.popcnt(module.i32.const(-10)), + module.f32.neg(module.f32.const(-33.612)), + module.f64.abs(module.f64.const(-9005.841)), + module.f32.ceil(module.f32.const(-33.612)), + module.f64.floor(module.f64.const(-9005.841)), + module.f32.trunc(module.f32.const(-33.612)), + module.f32.nearest(module.f32.const(-33.612)), + module.f64.sqrt(module.f64.const(-9005.841)), + 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.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)), + module.i64.trunc_u.f32(module.f32.const(-33.612)), + module.i32.trunc_s.f64(module.f64.const(-9005.841)), + module.i64.trunc_s.f64(module.f64.const(-9005.841)), + module.i32.trunc_u.f64(module.f64.const(-9005.841)), + module.i64.trunc_u.f64(module.f64.const(-9005.841)), + module.i32.reinterpret(module.f32.const(-33.612)), + module.i64.reinterpret(module.f64.const(-9005.841)), + module.f32.convert_s.i32(module.i32.const(-10)), + 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.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)), + // Binary + 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.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.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.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.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.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.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.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)), + module.f32.ge(module.f32.const(-33.612), module.f32.const(-62.5)), + // All the rest + module.block('', []), // block with no name + module.if(temp1, temp2, temp3), + module.if(temp4, temp5), + module.loop("in", makeInt32(0)), + module.loop(null, makeInt32(0)), + module.break("the-value", temp6, temp7), + module.break("the-nothing", makeInt32(2)), + module.break("the-value", null, makeInt32(3)), + module.break("the-nothing"), + 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.i32.eqz( // check the output type of the call node + module.i32.trunc_s.f32( + module.callImport("an-imported", [ makeInt32(13), makeFloat64(3.7) ], Binaryen.f32) + ) + ), + module.i32.eqz( // check the output type of the call node + module.callIndirect(makeInt32(2449), [ makeInt32(13), makeInt64(37, 0), makeFloat32(1.3), makeFloat64(3.7) ], "iiIfF") + ), + module.drop(module.getLocal(0, Binaryen.i32)), + module.setLocal(0, makeInt32(101)), + module.drop(module.teeLocal(0, makeInt32(102))), + module.i32.load(0, 0, makeInt32(1)), + module.i64.load16_s(2, 1, makeInt32(8)), + module.f32.load(0, 0, makeInt32(2)), + module.f64.load(2, 8, makeInt32(9)), + module.i32.store(0, 0, temp13, temp14), + module.i64.store(2, 4, temp15, temp16), + module.select(temp10, temp11, temp12), + module.return(makeInt32(1337)), + // TODO: Host + module.nop(), + module.unreachable(), + ]; + + console.log(Binaryen.emitText(valueList[3])); // test printing a standalone expression + + // Make the main body of the function. and one block with a return value, one without + var value = module.block("the-value", valueList); + var droppedValue = module.drop(value); + var nothing = module.block("the-nothing", [ droppedValue ]); + var body = module.block("the-body", [ nothing, makeInt32(42) ]); + + // Create the function + var sinker = module.addFunction("kitchen()sinker", iiIfF, [ Binaryen.i32 ], body); + + // Imports + + var fiF = module.addFunctionType("fiF", Binaryen.f32, [ Binaryen.i32, Binaryen.f64 ]); + module.addImport("an-imported", "module", "base", fiF); + + // Exports + + module.addExport("kitchen()sinker", "kitchen_sinker"); + + // Function table. One per module + + module.setFunctionTable([ sinker ]); + + // Memory. One per module + + module.setMemory(1, 256, "mem", [{ + offset: module.i32.const(10), + data: "hello, world".split('').map(function(x) { return x.charCodeAt(0) }) + }]); + + // Start function. One per module + + var v = module.addFunctionType("v", Binaryen.None, []); + var starter = module.addFunction("starter", v, [], module.nop()); + module.setStart(starter); + + // Unnamed function type + + var noname = module.addFunctionType(null, Binaryen.None, []); + + // A bunch of our code needs drop, auto-add it + module.autoDrop(); + + // Verify it validates + assert(module.validate()); + + // Print it out + console.log(module.emitText()); + + // Clean up the module, which owns all the objects we created above + module.dispose(); +} + +function makeCallCheck(x) { + return module.callImport("check", [ makeInt32(x) ], Binaryen.None); +} + +function test_relooper() { + module = new Binaryen.Module(); + var v = module.addFunctionType("v", Binaryen.None, []); + var localTypes = [ Binaryen.i32 ]; + + { + var vi = module.addFunctionType("vi", Binaryen.None, [ Binaryen.i32 ]); + module.addImport("check", "module", "check", vi); + } + + { // trivial: just one block + var relooper = new Binaryen.Relooper(); + var block = relooper.addBlock(makeCallCheck(1337)); + var body = relooper.renderAndDispose(block, 0, module); + module.addFunction("just-one-block", v, localTypes, body); + } + { // two blocks + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + relooper.addBranch(block0, block1); // no condition, no code on branch + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("two-blocks", v, localTypes, body); + } + { // two blocks with code between them + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + relooper.addBranch(block0, block1, null, makeDroppedInt32(77)); // code on branch + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("two-blocks-plus-code", v, localTypes, body); + } + { // two blocks in a loop + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + relooper.addBranch(block0, block1, null, null); + relooper.addBranch(block1, block0, null, null); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("loop", v, localTypes, body); + } + { // two blocks in a loop with codes + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + relooper.addBranch(block0, block1, null, makeDroppedInt32(33)); + relooper.addBranch(block1, block0, null, makeDroppedInt32(-66)); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("loop-plus-code", v, localTypes, body); + } + { // split + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + relooper.addBranch(block0, block1, makeInt32(55), null); + relooper.addBranch(block0, block2, null, null); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("split", v, localTypes, body); + } + { // split + code + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + temp = makeDroppedInt32(10); + relooper.addBranch(block0, block1, makeInt32(55), temp); + relooper.addBranch(block0, block2, null, makeDroppedInt32(20)); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("split-plus-code", v, localTypes, body); + } + { // if + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + relooper.addBranch(block0, block1, makeInt32(55), null); + relooper.addBranch(block0, block2, null, null); + relooper.addBranch(block1, block2, null, null); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("if", v, localTypes, body); + } + { // if + code + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + temp = makeDroppedInt32(-1); + relooper.addBranch(block0, block1, makeInt32(55), temp); + relooper.addBranch(block0, block2, null, makeDroppedInt32(-2)); + relooper.addBranch(block1, block2, null, makeDroppedInt32(-3)); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("if-plus-code", v, localTypes, body); + } + { // if-else + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + var block3 = relooper.addBlock(makeCallCheck(3)); + relooper.addBranch(block0, block1, makeInt32(55), null); + relooper.addBranch(block0, block2, null, null); + relooper.addBranch(block1, block3, null, null); + relooper.addBranch(block2, block3, null, null); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("if-else", v, localTypes, body); + } + { // loop+tail + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + relooper.addBranch(block0, block1, null, null); + relooper.addBranch(block1, block0, makeInt32(10), null); + relooper.addBranch(block1, block2, null, null); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("loop-tail", v, localTypes, body); + } + { // nontrivial loop + phi to head + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + var block3 = relooper.addBlock(makeCallCheck(3)); + var block4 = relooper.addBlock(makeCallCheck(4)); + var block5 = relooper.addBlock(makeCallCheck(5)); + var block6 = relooper.addBlock(makeCallCheck(6)); + relooper.addBranch(block0, block1, null, makeDroppedInt32(10)); + relooper.addBranch(block1, block2, makeInt32(-2), null); + relooper.addBranch(block1, block6, null, makeDroppedInt32(20)); + relooper.addBranch(block2, block3, makeInt32(-6), null); + relooper.addBranch(block2, block1, null, makeDroppedInt32(30)); + relooper.addBranch(block3, block4, makeInt32(-10), null); + relooper.addBranch(block3, block5, null, null); + relooper.addBranch(block4, block5, null, null); + relooper.addBranch(block5, block6, null, makeDroppedInt32(40)); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("nontrivial-loop-plus-phi-to-head", v, localTypes, body); + } + { // switch + var relooper = new Binaryen.Relooper(); + temp = makeInt32(-99); + var block0 = relooper.addBlockWithSwitch(makeCallCheck(0), temp); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + var block3 = relooper.addBlock(makeCallCheck(3)); + relooper.addBranchForSwitch(block0, block1, [ 2, 5 ]); + relooper.addBranchForSwitch(block0, block2, [4], makeDroppedInt32(55)); + relooper.addBranchForSwitch(block0, block3, [], null); + var body = relooper.renderAndDispose(block0, 0, module); + module.addFunction("switch", v, localTypes, body); + } + { // duff's device + var relooper = new Binaryen.Relooper(); + var block0 = relooper.addBlock(makeCallCheck(0)); + var block1 = relooper.addBlock(makeCallCheck(1)); + var block2 = relooper.addBlock(makeCallCheck(2)); + relooper.addBranch(block0, block1, makeInt32(10), null); + relooper.addBranch(block0, block2, null, null); + relooper.addBranch(block1, block2, null, null); + relooper.addBranch(block2, block1, null, null); + var body = relooper.renderAndDispose(block0, 3, module); // use $3 as the helper var + module.addFunction("duffs-device", v, [ Binaryen.i32, Binaryen.i32, Binaryen.i64, Binaryen.i32, Binaryen.f32, Binaryen.f64, Binaryen.i32 ], body); + } + + var i = module.addFunctionType("i", Binaryen.i32, []); + + { // return in a block + var relooper = new Binaryen.Relooper(); + var list = module.block("the-list", [ makeCallCheck(42), module.return(makeInt32(1337)) ]); + var block = relooper.addBlock(list); + var body = relooper.renderAndDispose(block, 0, module); + module.addFunction("return", i, localTypes, body); + } + + console.log("raw:"); + console.log(module.emitText()); + + assert(module.validate()); + + module.optimize(); + + assert(module.validate()); + + console.log("optimized:"); + console.log(module.emitText()); + + module.dispose(); +} + +function test_binaries() { + var buffer, size; + + { // create a module and write it to binary + module = new Binaryen.Module(); + var iii = module.addFunctionType("iii", Binaryen.i32, [ Binaryen.i32, Binaryen.i32 ]); + var x = module.getLocal(0, Binaryen.i32), + y = module.getLocal(1, Binaryen.i32); + var add = module.i32.add(x, y); + var adder = module.addFunction("adder", iii, [], add); + buffer = module.emitBinary(); + size = buffer.length; // write out the module + module.dispose(); + } + + assert(size > 0); + assert(size < 512); // this is a tiny module + + // read the module from the binary + module = Binaryen.readBinary(buffer, size); + + // validate, print, and free + assert(module.validate()); + console.log("module loaded from binary form:"); + console.log(module.emitText()); + module.dispose(); +} + +function test_interpret() { + // create a simple module with a start method that prints a number, and interpret it, printing that number. + module = new Binaryen.Module(); + + var vi = module.addFunctionType("vi", Binaryen.None, [ Binaryen.i32 ]); + module.addImport("print-i32", "spectest", "print", vi); + + var v = module.addFunctionType("v", Binaryen.None, []); + call = module.callImport("print-i32", [ makeInt32(1234) ], Binaryen.None); + var starter = module.addFunction("starter", v, [], call); + module.setStart(starter); + + console.log(module.emitText()); + assert(module.validate()); + module.interpret(); + module.dispose(); +} + +function test_nonvalid() { + // create a module that fails to validate + module = new Binaryen.Module(); + + var v = module.addFunctionType("v", Binaryen.None, []); + var func = module.addFunction("func", v, [ Binaryen.i32 ], + module.setLocal(0, makeInt64(1234, 0)) // wrong type! + ); + + console.log(module.emitText()); + console.log("validation: " + module.validate()); + + module.dispose(); +} + +function test_tracing() { + Binaryen.setAPITracing(1); + test_core(); + test_relooper(); + Binaryen.setAPITracing(0); +} + +function main() { + test_types(); + test_core(); + test_relooper(); + test_binaries(); + test_interpret(); + test_nonvalid(); + test_tracing(); +} + +main(); + |