diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-11-21 08:59:13 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-21 08:59:13 -0800 |
commit | 6cc2bb302d5729c76da42dc0815d6dbba645d952 (patch) | |
tree | 11e60856b2028e73df98eeaea2f0b789c50c8cd1 /test/example/relooper-fuzz2.c | |
parent | 44335674936254ef6f8695883e4376a9d5fd1521 (diff) | |
download | binaryen-6cc2bb302d5729c76da42dc0815d6dbba645d952.tar.gz binaryen-6cc2bb302d5729c76da42dc0815d6dbba645d952.tar.bz2 binaryen-6cc2bb302d5729c76da42dc0815d6dbba645d952.zip |
Relooper CFG optimizations (#1759)
Previously the relooper would do some optimizations when deciding when to use an if vs a switch, how to group blocks, etc. This PR adds an additional pre-optimization phase with some basic but useful simplify-cfg style passes,
* Skip empty blocks when they have just one exit.
* Merge exiting branches when they are equivalent.
* Canonicalize block contents to make such comparisons more useful.
* Turn a trivial one-target switch into a simple branch.
This can help in noticeable ways when running the rereloop pass, e.g. on LLVM wasm backend output.
Also:
* Binaryen C API changes to the relooper, which now gets a Module for its constructor. It needs it for the optimizations, as it may construct new nodes.
* Many relooper-fuzzer improvements.
* Clean up HashType usage.
Diffstat (limited to 'test/example/relooper-fuzz2.c')
-rw-r--r-- | test/example/relooper-fuzz2.c | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/test/example/relooper-fuzz2.c b/test/example/relooper-fuzz2.c new file mode 100644 index 000000000..ad687f918 --- /dev/null +++ b/test/example/relooper-fuzz2.c @@ -0,0 +1,509 @@ + + +#include <assert.h> +#include <stdio.h> + +#include "binaryen-c.h" + +// globals: address 4 is index +// decisions are at address 8+ + +int main() { + BinaryenModuleRef module = BinaryenModuleCreate(); + + // check() + + // if the end, halt + BinaryenExpressionRef halter = BinaryenIf(module, + BinaryenBinary(module, + BinaryenGeUInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 27)) // jumps of 4 bytes + ), + BinaryenUnreachable(module), + NULL + ); + // increment index + BinaryenExpressionRef incer = BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4)) + ), + BinaryenTypeInt32() + ); + + // optionally, print the return value + BinaryenExpressionRef args[] = { + BinaryenBinary(module, + BinaryenSubInt32(), + BinaryenConst(module, BinaryenLiteralInt32(0)), + BinaryenLoad(module, + 4, 0, 4, 0, BinaryenTypeInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))) + ) + ) + }; + BinaryenExpressionRef debugger; + if (1) debugger = BinaryenCall(module, "print", args, 1, + BinaryenTypeNone()); + else debugger = BinaryenNop(module); + + // return the decision. need to subtract 4 that we just added, + // and add 8 since that's where we start, so overall offset 4 + BinaryenExpressionRef returner = BinaryenLoad(module, + 4, 0, 4, 0, BinaryenTypeInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))) + ); + BinaryenExpressionRef checkBodyList[] = { halter, incer, debugger, + returner }; + BinaryenExpressionRef checkBody = BinaryenBlock(module, + NULL, checkBodyList, sizeof(checkBodyList) / sizeof(BinaryenExpressionRef), + BinaryenTypeInt32() + ); + BinaryenFunctionTypeRef i = BinaryenAddFunctionType(module, "i", + BinaryenTypeInt32(), + NULL, 0); + BinaryenAddFunction(module, "check", i, NULL, 0, checkBody); + + // contents of main() begin here + + RelooperRef relooper = RelooperCreate(module); + + + RelooperBlockRef b0; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b0 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone())); + + } + + RelooperBlockRef b1; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b1 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone())); + + } + + RelooperBlockRef b2; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b2 = RelooperAddBlockWithSwitch(relooper, + BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()), + BinaryenBinary(module, + BinaryenRemUInt32(), + BinaryenGetLocal(module, 0, BinaryenTypeInt32()), + BinaryenConst(module, BinaryenLiteralInt32(2)) + ) + ); + + } + + RelooperBlockRef b3; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b3 = RelooperAddBlockWithSwitch(relooper, + BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()), + BinaryenBinary(module, + BinaryenRemUInt32(), + BinaryenGetLocal(module, 0, BinaryenTypeInt32()), + BinaryenConst(module, BinaryenLiteralInt32(1)) + ) + ); + + } + + RelooperBlockRef b4; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(4)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b4 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone())); + + } + + RelooperBlockRef b5; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b5 = RelooperAddBlockWithSwitch(relooper, + BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()), + BinaryenBinary(module, + BinaryenRemUInt32(), + BinaryenGetLocal(module, 0, BinaryenTypeInt32()), + BinaryenConst(module, BinaryenLiteralInt32(1)) + ) + ); + + } + + RelooperBlockRef b6; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(6)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b6 = RelooperAddBlockWithSwitch(relooper, + BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()), + BinaryenBinary(module, + BinaryenRemUInt32(), + BinaryenGetLocal(module, 0, BinaryenTypeInt32()), + BinaryenConst(module, BinaryenLiteralInt32(3)) + ) + ); + + } + + RelooperBlockRef b7; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b7 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone())); + + } + + RelooperBlockRef b8; + { + BinaryenExpressionRef args[] = { + BinaryenConst(module, BinaryenLiteralInt32(0)) + }; + BinaryenExpressionRef list[] = { + BinaryenCall(module, "print", args, 1, BinaryenTypeNone()), + BinaryenSetLocal(module, 0, BinaryenCall(module, "check", NULL, 0, + BinaryenTypeInt32())) + }; + + b8 = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone())); + + } + + RelooperAddBranch(b0, b1, NULL, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 4)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranch(b1, b1, NULL, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 4)) + ), + BinaryenTypeInt32() + )); + + { + BinaryenIndex values[] = { 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86 }; + RelooperAddBranchForSwitch(b2, b7, values, + sizeof(values) / sizeof(BinaryenIndex), + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 6)) + ), + BinaryenTypeInt32() + )); + } + + RelooperAddBranchForSwitch(b2, b4, NULL, 0, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 4)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranchForSwitch(b3, b6, NULL, 0, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 5)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranch(b4, b7, BinaryenBinary(module, + BinaryenEqInt32(), + BinaryenBinary(module, + BinaryenRemUInt32(), + BinaryenGetLocal(module, 0, BinaryenTypeInt32()), + BinaryenConst(module, BinaryenLiteralInt32(2)) + ), + BinaryenConst(module, BinaryenLiteralInt32(0)) + ), + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 5)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranch(b4, b3, NULL, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 3)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranchForSwitch(b5, b1, NULL, 0, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 4)) + ), + BinaryenTypeInt32() + )); + + { + BinaryenIndex values[] = { 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108 }; + RelooperAddBranchForSwitch(b6, b1, values, + sizeof(values) / sizeof(BinaryenIndex), + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 2)) + ), + BinaryenTypeInt32() + )); + } + + { + BinaryenIndex values[] = { 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136,139,142,145,148,151,154,157,160 }; + RelooperAddBranchForSwitch(b6, b7, values, + sizeof(values) / sizeof(BinaryenIndex), + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 3)) + ), + BinaryenTypeInt32() + )); + } + + RelooperAddBranchForSwitch(b6, b2, NULL, 0, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 3)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranch(b7, b5, BinaryenBinary(module, + BinaryenEqInt32(), + BinaryenBinary(module, + BinaryenRemUInt32(), + BinaryenGetLocal(module, 0, BinaryenTypeInt32()), + BinaryenConst(module, BinaryenLiteralInt32(2)) + ), + BinaryenConst(module, BinaryenLiteralInt32(0)) + ), + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 1)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranch(b7, b1, NULL, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 4)) + ), + BinaryenTypeInt32() + )); + + RelooperAddBranch(b8, b8, NULL, + BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(4)), + BinaryenBinary(module, + BinaryenAddInt32(), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), + BinaryenConst(module, BinaryenLiteralInt32(4))), + BinaryenConst(module, BinaryenLiteralInt32(4 * 2)) + ), + BinaryenTypeInt32() + )); + + BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1); + + int decisions[] = { 5, 111, 119, 17, 179, 41, 32, 3, 171, 126, 13, 95, 70, 91, 9, 140, 99, 161, 38, 87, 153, 117, 140, 11, 157, 48, 4 }; + int numDecisions = sizeof(decisions)/sizeof(int); + + // write out all the decisions, then the body of the function + BinaryenExpressionRef full[numDecisions + 1]; + + { + int i; + for (i = 0; i < numDecisions; i++) { + full[i] = BinaryenStore(module, + 4, 0, 0, + BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)), + BinaryenConst(module, BinaryenLiteralInt32(decisions[i])), + BinaryenTypeInt32() + ); + } + } + full[numDecisions] = body; + BinaryenExpressionRef all = BinaryenBlock(module, NULL, full, + numDecisions + 1, + BinaryenTypeNone()); + + BinaryenFunctionTypeRef v = BinaryenAddFunctionType(module, "v", + BinaryenTypeNone(), + NULL, 0); + // locals: state, free-for-label + BinaryenType localTypes[] = { BinaryenTypeInt32(), BinaryenTypeInt32() }; + BinaryenFunctionRef theMain = BinaryenAddFunction(module, "main", v, + localTypes, 2, all); + BinaryenSetStart(module, theMain); + + // import + + BinaryenType iparams[] = { BinaryenTypeInt32() }; + BinaryenFunctionTypeRef vi = BinaryenAddFunctionType(module, "vi", + BinaryenTypeNone(), + iparams, 1); + BinaryenAddFunctionImport(module, "print", "spectest", "print", vi); + + // memory + BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, 0, 0); + + // optionally, optimize + if (0) BinaryenModuleOptimize(module); + + assert(BinaryenModuleValidate(module)); + + // write it out + + BinaryenModulePrint(module); + + BinaryenModuleDispose(module); + + return 0; +} |