diff options
author | Daniel Wirtz <dcode@dcode.io> | 2020-04-20 23:01:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-20 14:01:26 -0700 |
commit | 483d759230f4693abfca3a74a97b1c1db6d2a0d6 (patch) | |
tree | c37b39802b9e5791abb3e329b88ba7185557de49 /test/binaryen.js | |
parent | 1dc820c913712a2c50d05caee77e90a7ec49d2e1 (diff) | |
download | binaryen-483d759230f4693abfca3a74a97b1c1db6d2a0d6.tar.gz binaryen-483d759230f4693abfca3a74a97b1c1db6d2a0d6.tar.bz2 binaryen-483d759230f4693abfca3a74a97b1c1db6d2a0d6.zip |
Refactor expression runner so it can be used via the C and JS APIs (#2702)
Refactors most of the precompute pass's expression runner into its
base class so it can also be used via the C and JS APIs. Also adds
the option to populate the runner with known constant local and global
values upfront, and remembers assigned intermediate values as well
as traversing into functions if requested.
Diffstat (limited to 'test/binaryen.js')
-rw-r--r-- | test/binaryen.js/custom-section.js.txt | 1 | ||||
-rw-r--r-- | test/binaryen.js/expressionrunner.js | 208 | ||||
-rw-r--r-- | test/binaryen.js/expressionrunner.js.txt | 161 | ||||
-rw-r--r-- | test/binaryen.js/inlining-options.js.txt | 1 | ||||
-rw-r--r-- | test/binaryen.js/kitchen-sink.js.txt | 3 | ||||
-rw-r--r-- | test/binaryen.js/low-memory-unused.js.txt | 1 | ||||
-rw-r--r-- | test/binaryen.js/pass-arguments.js.txt | 1 |
7 files changed, 376 insertions, 0 deletions
diff --git a/test/binaryen.js/custom-section.js.txt b/test/binaryen.js/custom-section.js.txt index 063ef9dde..7c68582f1 100644 --- a/test/binaryen.js/custom-section.js.txt +++ b/test/binaryen.js/custom-section.js.txt @@ -10,6 +10,7 @@ int main() { std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; + std::map<size_t, ExpressionRunnerRef> expressionRunners; BinaryenModuleRef the_module = NULL; RelooperRef the_relooper = NULL; the_module = BinaryenModuleCreate(); diff --git a/test/binaryen.js/expressionrunner.js b/test/binaryen.js/expressionrunner.js new file mode 100644 index 000000000..35117c453 --- /dev/null +++ b/test/binaryen.js/expressionrunner.js @@ -0,0 +1,208 @@ +var Flags = binaryen.ExpressionRunner.Flags; +console.log("// ExpressionRunner.Flags.Default = " + Flags.Default); +console.log("// ExpressionRunner.Flags.PreserveSideeffects = " + Flags.PreserveSideeffects); +console.log("// ExpressionRunner.Flags.TraverseCalls = " + Flags.TraverseCalls); + +binaryen.setAPITracing(true); + +function assertDeepEqual(x, y) { + if (typeof x === "object") { + for (let i in x) assertDeepEqual(x[i], y[i]); + for (let i in y) assertDeepEqual(x[i], y[i]); + } else { + assert(x === y); + } +} + +var module = new binaryen.Module(); +module.addGlobal("aGlobal", binaryen.i32, true, module.i32.const(0)); + +// Should evaluate down to a constant +var runner = new binaryen.ExpressionRunner(module); +var expr = runner.runAndDispose( + module.i32.add( + module.i32.const(1), + module.i32.const(2) + ) +); +assertDeepEqual( + binaryen.getExpressionInfo(expr), + { + id: binaryen.ExpressionIds.Const, + type: binaryen.i32, + value: 3 + } +); + +// Should traverse control structures +runner = new binaryen.ExpressionRunner(module); +expr = runner.runAndDispose( + module.i32.add( + module.i32.const(1), + module.if( + module.i32.const(0), + module.i32.const(0), + module.i32.const(3) + ) + ), +); +assertDeepEqual( + binaryen.getExpressionInfo(expr), + { + id: binaryen.ExpressionIds.Const, + type: binaryen.i32, + value: 4 + } +); + +// Should be unable to evaluate a local if not explicitly specified +runner = new binaryen.ExpressionRunner(module); +expr = runner.runAndDispose( + module.i32.add( + module.local.get(0, binaryen.i32), + module.i32.const(1) + ) +); +assert(expr === 0); + +// Should handle traps properly +runner = new binaryen.ExpressionRunner(module); +expr = runner.runAndDispose( + module.unreachable() +); +assert(expr === 0); + +// Should ignore `local.tee` side-effects if just evaluating the expression +runner = new binaryen.ExpressionRunner(module); +expr = runner.runAndDispose( + module.i32.add( + module.local.tee(0, module.i32.const(4), binaryen.i32), + module.i32.const(1) + ) +); +assertDeepEqual( + binaryen.getExpressionInfo(expr), + { + id: binaryen.ExpressionIds.Const, + type: binaryen.i32, + value: 5 + } +); + +// Should preserve any side-effects if explicitly requested +runner = new binaryen.ExpressionRunner(module, Flags.PreserveSideeffects); +expr = runner.runAndDispose( + module.i32.add( + module.local.tee(0, module.i32.const(4), binaryen.i32), + module.i32.const(1) + ) +); +assert(expr === 0); + +// Should work with temporary values if just evaluating the expression +runner = new binaryen.ExpressionRunner(module); +expr = runner.runAndDispose( + module.i32.add( + module.block(null, [ + module.local.set(0, module.i32.const(2)), + module.local.get(0, binaryen.i32) + ], binaryen.i32), + module.block(null, [ + module.global.set("aGlobal", module.i32.const(4)), + module.global.get("aGlobal", binaryen.i32) + ], binaryen.i32) + ) +); +assertDeepEqual( + binaryen.getExpressionInfo(expr), + { + id: binaryen.ExpressionIds.Const, + type: binaryen.i32, + value: 6 + } +); + +// Should pick up explicitly preset values +runner = new binaryen.ExpressionRunner(module, Flags.PreserveSideeffects); +assert(runner.setLocalValue(0, module.i32.const(3))); +assert(runner.setGlobalValue("aGlobal", module.i32.const(4))); +expr = runner.runAndDispose( + module.i32.add( + module.local.get(0, binaryen.i32), + module.global.get("aGlobal", binaryen.i32) + ) +); +assertDeepEqual( + binaryen.getExpressionInfo(expr), + { + id: binaryen.ExpressionIds.Const, + type: binaryen.i32, + value: 7 + } +); + +// Should traverse into (simple) functions if requested +runner = new binaryen.ExpressionRunner(module, Flags.TraverseCalls); +module.addFunction("add", binaryen.createType([ binaryen.i32, binaryen.i32 ]), binaryen.i32, [], + module.block(null, [ + module.i32.add( + module.local.get(0, binaryen.i32), + module.local.get(1, binaryen.i32) + ) + ], binaryen.i32) +); +assert(runner.setLocalValue(0, module.i32.const(1))); +expr = runner.runAndDispose( + module.i32.add( + module.i32.add( + module.local.get(0, binaryen.i32), + module.call("add", [ + module.i32.const(2), + module.i32.const(4) + ], binaryen.i32) + ), + module.local.get(0, binaryen.i32) + ) +); +assertDeepEqual( + binaryen.getExpressionInfo(expr), + { + id: binaryen.ExpressionIds.Const, + type: binaryen.i32, + value: 8 + } +); + +// Should not attempt to traverse into functions if not explicitly set +runner = new binaryen.ExpressionRunner(module); +expr = runner.runAndDispose( + module.i32.add( + module.i32.const(1), + module.call("add", [ + module.i32.const(3), + module.i32.const(4) + ], binaryen.i32) + ) +); +assert(expr === 0); + +// Should stop on maxDepth +runner = new binaryen.ExpressionRunner(module, Flags.Default, 1); +expr = runner.runAndDispose( + module.block(null, [ + module.i32.const(1), + ], binaryen.i32) +); +assert(expr === 0); + +// Should not loop infinitely +runner = new binaryen.ExpressionRunner(module, Flags.Default, 50, 3); +expr = runner.runAndDispose( + module.loop("theLoop", + module.br("theLoop") + ) +); +assert(expr === 0); + +module.dispose(); +binaryen.setAPITracing(false); diff --git a/test/binaryen.js/expressionrunner.js.txt b/test/binaryen.js/expressionrunner.js.txt new file mode 100644 index 000000000..4d74c9feb --- /dev/null +++ b/test/binaryen.js/expressionrunner.js.txt @@ -0,0 +1,161 @@ +// ExpressionRunner.Flags.Default = 0 +// ExpressionRunner.Flags.PreserveSideeffects = 1 +// ExpressionRunner.Flags.TraverseCalls = 2 +// beginning a Binaryen API trace +#include <math.h> +#include <map> +#include "binaryen-c.h" +int main() { + std::map<size_t, BinaryenType> types; + std::map<size_t, BinaryenExpressionRef> expressions; + std::map<size_t, BinaryenFunctionRef> functions; + std::map<size_t, BinaryenGlobalRef> globals; + std::map<size_t, BinaryenEventRef> events; + std::map<size_t, BinaryenExportRef> exports; + std::map<size_t, RelooperBlockRef> relooperBlocks; + std::map<size_t, ExpressionRunnerRef> expressionRunners; + BinaryenModuleRef the_module = NULL; + RelooperRef the_relooper = NULL; + the_module = BinaryenModuleCreate(); + expressions[size_t(NULL)] = BinaryenExpressionRef(NULL); + expressions[1] = BinaryenConst(the_module, BinaryenLiteralInt32(0)); + globals[0] = BinaryenAddGlobal(the_module, "aGlobal", BinaryenTypeInt32(), 1, expressions[1]); + expressionRunners[0] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[2] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + expressions[3] = BinaryenConst(the_module, BinaryenLiteralInt32(2)); + expressions[4] = BinaryenBinary(the_module, 0, expressions[2], expressions[3]); + expressions[5] = ExpressionRunnerRunAndDispose(expressionRunners[0], expressions[4]); + BinaryenExpressionGetId(expressions[5]); + BinaryenExpressionGetType(expressions[5]); + BinaryenConstGetValueI32(expressions[5]); + expressionRunners[1] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[6] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + expressions[7] = BinaryenConst(the_module, BinaryenLiteralInt32(0)); + expressions[8] = BinaryenConst(the_module, BinaryenLiteralInt32(0)); + expressions[9] = BinaryenConst(the_module, BinaryenLiteralInt32(3)); + expressions[10] = BinaryenIf(the_module, expressions[7], expressions[8], expressions[9]); + expressions[11] = BinaryenBinary(the_module, 0, expressions[6], expressions[10]); + expressions[12] = ExpressionRunnerRunAndDispose(expressionRunners[1], expressions[11]); + BinaryenExpressionGetId(expressions[12]); + BinaryenExpressionGetType(expressions[12]); + BinaryenConstGetValueI32(expressions[12]); + expressionRunners[2] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[13] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32()); + expressions[14] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + expressions[15] = BinaryenBinary(the_module, 0, expressions[13], expressions[14]); + ExpressionRunnerRunAndDispose(expressionRunners[2], expressions[15]); + expressionRunners[3] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[16] = BinaryenUnreachable(the_module); + ExpressionRunnerRunAndDispose(expressionRunners[3], expressions[16]); + expressionRunners[4] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[17] = BinaryenConst(the_module, BinaryenLiteralInt32(4)); + expressions[18] = BinaryenLocalTee(the_module, 0, expressions[17], BinaryenTypeInt32()); + expressions[19] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + expressions[20] = BinaryenBinary(the_module, 0, expressions[18], expressions[19]); + expressions[21] = ExpressionRunnerRunAndDispose(expressionRunners[4], expressions[20]); + BinaryenExpressionGetId(expressions[21]); + BinaryenExpressionGetType(expressions[21]); + BinaryenConstGetValueI32(expressions[21]); + expressionRunners[5] = ExpressionRunnerCreate(the_module, 1, 0, 0); + expressions[22] = BinaryenConst(the_module, BinaryenLiteralInt32(4)); + expressions[23] = BinaryenLocalTee(the_module, 0, expressions[22], BinaryenTypeInt32()); + expressions[24] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + expressions[25] = BinaryenBinary(the_module, 0, expressions[23], expressions[24]); + ExpressionRunnerRunAndDispose(expressionRunners[5], expressions[25]); + expressionRunners[6] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[26] = BinaryenConst(the_module, BinaryenLiteralInt32(2)); + expressions[27] = BinaryenLocalSet(the_module, 0, expressions[26]); + expressions[28] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32()); + { + BinaryenExpressionRef children[] = { expressions[27], expressions[28] }; + expressions[29] = BinaryenBlock(the_module, NULL, children, 2, BinaryenTypeInt32()); + } + expressions[30] = BinaryenConst(the_module, BinaryenLiteralInt32(4)); + expressions[31] = BinaryenGlobalSet(the_module, "aGlobal", expressions[30]); + expressions[32] = BinaryenGlobalGet(the_module, "aGlobal", BinaryenTypeInt32()); + { + BinaryenExpressionRef children[] = { expressions[31], expressions[32] }; + expressions[33] = BinaryenBlock(the_module, NULL, children, 2, BinaryenTypeInt32()); + } + expressions[34] = BinaryenBinary(the_module, 0, expressions[29], expressions[33]); + expressions[35] = ExpressionRunnerRunAndDispose(expressionRunners[6], expressions[34]); + BinaryenExpressionGetId(expressions[35]); + BinaryenExpressionGetType(expressions[35]); + BinaryenConstGetValueI32(expressions[35]); + expressionRunners[7] = ExpressionRunnerCreate(the_module, 1, 0, 0); + expressions[36] = BinaryenConst(the_module, BinaryenLiteralInt32(3)); + ExpressionRunnerSetLocalValue(expressionRunners[7], 0, expressions[36]); + expressions[37] = BinaryenConst(the_module, BinaryenLiteralInt32(4)); + ExpressionRunnerSetGlobalValue(expressionRunners[7], "aGlobal", expressions[37]); + expressions[38] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32()); + expressions[39] = BinaryenGlobalGet(the_module, "aGlobal", BinaryenTypeInt32()); + expressions[40] = BinaryenBinary(the_module, 0, expressions[38], expressions[39]); + expressions[41] = ExpressionRunnerRunAndDispose(expressionRunners[7], expressions[40]); + BinaryenExpressionGetId(expressions[41]); + BinaryenExpressionGetType(expressions[41]); + BinaryenConstGetValueI32(expressions[41]); + expressionRunners[8] = ExpressionRunnerCreate(the_module, 2, 0, 0); + { + BinaryenType t0[] = {BinaryenTypeInt32(), BinaryenTypeInt32()}; + types[0] = BinaryenTypeCreate(t0, 2); + } + expressions[42] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32()); + expressions[43] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32()); + expressions[44] = BinaryenBinary(the_module, 0, expressions[42], expressions[43]); + { + BinaryenExpressionRef children[] = { expressions[44] }; + expressions[45] = BinaryenBlock(the_module, NULL, children, 1, BinaryenTypeInt32()); + } + { + BinaryenType varTypes[] = { 0 }; + functions[0] = BinaryenAddFunction(the_module, "add", types[0], BinaryenTypeInt32(), varTypes, 0, expressions[45]); + } + expressions[46] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + ExpressionRunnerSetLocalValue(expressionRunners[8], 0, expressions[46]); + expressions[47] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32()); + expressions[48] = BinaryenConst(the_module, BinaryenLiteralInt32(2)); + expressions[49] = BinaryenConst(the_module, BinaryenLiteralInt32(4)); + { + BinaryenExpressionRef operands[] = { expressions[48], expressions[49] }; + expressions[50] = BinaryenCall(the_module, "add", operands, 2, BinaryenTypeInt32()); + } + expressions[51] = BinaryenBinary(the_module, 0, expressions[47], expressions[50]); + expressions[52] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32()); + expressions[53] = BinaryenBinary(the_module, 0, expressions[51], expressions[52]); + expressions[54] = ExpressionRunnerRunAndDispose(expressionRunners[8], expressions[53]); + BinaryenExpressionGetId(expressions[54]); + BinaryenExpressionGetType(expressions[54]); + BinaryenConstGetValueI32(expressions[54]); + expressionRunners[9] = ExpressionRunnerCreate(the_module, 0, 0, 0); + expressions[55] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + expressions[56] = BinaryenConst(the_module, BinaryenLiteralInt32(3)); + expressions[57] = BinaryenConst(the_module, BinaryenLiteralInt32(4)); + { + BinaryenExpressionRef operands[] = { expressions[56], expressions[57] }; + expressions[58] = BinaryenCall(the_module, "add", operands, 2, BinaryenTypeInt32()); + } + expressions[59] = BinaryenBinary(the_module, 0, expressions[55], expressions[58]); + ExpressionRunnerRunAndDispose(expressionRunners[9], expressions[59]); + expressionRunners[10] = ExpressionRunnerCreate(the_module, 0, 1, 0); + expressions[60] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); + { + BinaryenExpressionRef children[] = { expressions[60] }; + expressions[61] = BinaryenBlock(the_module, NULL, children, 1, BinaryenTypeInt32()); + } + ExpressionRunnerRunAndDispose(expressionRunners[10], expressions[61]); + expressionRunners[11] = ExpressionRunnerCreate(the_module, 0, 50, 3); + expressions[62] = BinaryenBreak(the_module, "theLoop", expressions[0], expressions[0]); + expressions[63] = BinaryenLoop(the_module, "theLoop", expressions[62]); + ExpressionRunnerRunAndDispose(expressionRunners[11], expressions[63]); + BinaryenModuleDispose(the_module); + types.clear(); + expressions.clear(); + functions.clear(); + globals.clear(); + events.clear(); + exports.clear(); + relooperBlocks.clear(); + expressionRunners.clear(); + return 0; +} +// ending a Binaryen API trace diff --git a/test/binaryen.js/inlining-options.js.txt b/test/binaryen.js/inlining-options.js.txt index 077e366ce..91d360449 100644 --- a/test/binaryen.js/inlining-options.js.txt +++ b/test/binaryen.js/inlining-options.js.txt @@ -10,6 +10,7 @@ int main() { std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; + std::map<size_t, ExpressionRunnerRef> expressionRunners; BinaryenModuleRef the_module = NULL; RelooperRef the_relooper = NULL; BinaryenGetAlwaysInlineMaxSize(); diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 128c4ba51..7497e00a9 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -10,6 +10,7 @@ int main() { std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; + std::map<size_t, ExpressionRunnerRef> expressionRunners; BinaryenModuleRef the_module = NULL; RelooperRef the_relooper = NULL; the_module = BinaryenModuleCreate(); @@ -5462,6 +5463,7 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} events.clear(); exports.clear(); relooperBlocks.clear(); + expressionRunners.clear(); the_module = BinaryenModuleCreate(); expressions[size_t(NULL)] = BinaryenExpressionRef(NULL); BinaryenAddFunctionImport(the_module, "check", "module", "check", BinaryenTypeInt32(), BinaryenTypeNone()); @@ -6392,6 +6394,7 @@ optimized: events.clear(); exports.clear(); relooperBlocks.clear(); + expressionRunners.clear(); // BinaryenTypeNone: 0 // [] // BinaryenTypeUnreachable: 1 diff --git a/test/binaryen.js/low-memory-unused.js.txt b/test/binaryen.js/low-memory-unused.js.txt index 4933825a5..6f6e82d9b 100644 --- a/test/binaryen.js/low-memory-unused.js.txt +++ b/test/binaryen.js/low-memory-unused.js.txt @@ -54,6 +54,7 @@ int main() { std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; + std::map<size_t, ExpressionRunnerRef> expressionRunners; BinaryenModuleRef the_module = NULL; RelooperRef the_relooper = NULL; BinaryenSetLowMemoryUnused(1); diff --git a/test/binaryen.js/pass-arguments.js.txt b/test/binaryen.js/pass-arguments.js.txt index df98df08c..d13c4cad7 100644 --- a/test/binaryen.js/pass-arguments.js.txt +++ b/test/binaryen.js/pass-arguments.js.txt @@ -10,6 +10,7 @@ int main() { std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; + std::map<size_t, ExpressionRunnerRef> expressionRunners; BinaryenModuleRef the_module = NULL; RelooperRef the_relooper = NULL; BinaryenGetPassArgument("theKey"); |