diff options
-rw-r--r-- | src/passes/SimplifyLocals.cpp | 54 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | src/passes/passes.h | 3 | ||||
-rw-r--r-- | test/passes/simplify-locals-nostructure.txt | 38 | ||||
-rw-r--r-- | test/passes/simplify-locals-nostructure.wast | 15 | ||||
-rw-r--r-- | test/passes/simplify-locals-notee-nostructure.txt | 38 | ||||
-rw-r--r-- | test/passes/simplify-locals-notee-nostructure.wast | 15 | ||||
-rw-r--r-- | test/passes/simplify-locals-notee.txt | 34 | ||||
-rw-r--r-- | test/passes/simplify-locals-notee.wast | 15 | ||||
-rw-r--r-- | test/passes/simplify-locals.txt | 30 | ||||
-rw-r--r-- | test/passes/simplify-locals.wast | 12 |
11 files changed, 246 insertions, 11 deletions
diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index 7fef53dcc..852fbc0cd 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp @@ -31,6 +31,15 @@ // After this pass, some locals may be completely unused. reorder-locals // can get rid of those (the operation is trivial there after it sorts by use // frequency). +// +// This pass has two main options: +// +// * Tee: allow teeing, i.e., sinking a local with more than one use, +// and so after sinking we have a tee for the first use. +// * Structure: allow sinking of locals whose value is a control flow +// structure, an if or a block (and the value is thus the +// return value of the if/block). +// #include <wasm.h> #include <wasm-builder.h> @@ -64,7 +73,11 @@ struct SetLocalRemover : public PostWalker<SetLocalRemover, Visitor<SetLocalRemo struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, Visitor<SimplifyLocals>>> { bool isFunctionParallel() override { return true; } - Pass* create() override { return new SimplifyLocals; } + Pass* create() override { return new SimplifyLocals(allowTee, allowStructure); } + + bool allowTee, allowStructure; + + SimplifyLocals(bool allowTee, bool allowStructure) : allowTee(allowTee), allowStructure(allowStructure) {} // information for a set_local we can sink struct SinkableInfo { @@ -107,11 +120,11 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, // whether we need to run an additional cycle bool anotherCycle; - // whether this is the first cycle + // whether this is the first cycle, in which we always disallow teeing bool firstCycle; // local => # of get_locals for it - GetLocalCounter counter; + GetLocalCounter getCounter; static void doNoteNonLinear(SimplifyLocals* self, Expression** currp) { auto* curr = *currp; @@ -186,9 +199,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, if (found != sinkables.end()) { // sink it, and nop the origin auto* set = (*found->second.item)->cast<SetLocal>(); - if (firstCycle) { - // just one get_local of this, so just sink the value - assert(counter.num[curr->index] == 1); + if (firstCycle || getCounter.num[curr->index] == 1) { replaceCurrent(set->value); } else { replaceCurrent(set); @@ -264,7 +275,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, self->checkInvalidations(effects); } - if (set && !set->isTee() && (!self->firstCycle || self->counter.num[set->index] == 1)) { + if (set && self->canSink(set)) { Index index = set->index; assert(self->sinkables.count(index) == 0); self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp))); @@ -273,6 +284,15 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, self->expressionStack.pop_back(); } + bool canSink(SetLocal* set) { + // we can never move a tee + if (set->isTee()) return false; + // if in the first cycle, or not allowing tees, then we cannot sink if >1 use as that would make a tee + if ((firstCycle || !allowTee) && getCounter.num[set->index] > 1) return false; + if (!allowStructure && (set->value->is<If>() || set->value->is<Block>())) return false; + return true; + } + std::vector<Block*> blocksToEnlarge; std::vector<If*> ifsToEnlarge; @@ -415,7 +435,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, void doWalkFunction(Function* func) { // scan get_locals - counter.analyze(func); + getCounter.analyze(func); // multiple passes may be required per function, consider this: // x = load // y = store @@ -468,16 +488,28 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, // for a local with no remaining gets, in which case, we can // remove the set. // First, recount get_locals - counter.analyze(func); + getCounter.analyze(func); // Second, remove unneeded sets SetLocalRemover remover; - remover.numGetLocals = &counter.num; + remover.numGetLocals = &getCounter.num; remover.walkFunction(func); } }; Pass *createSimplifyLocalsPass() { - return new SimplifyLocals(); + return new SimplifyLocals(true, true); +} + +Pass *createSimplifyLocalsNoTeePass() { + return new SimplifyLocals(false, true); +} + +Pass *createSimplifyLocalsNoStructurePass() { + return new SimplifyLocals(true, false); +} + +Pass *createSimplifyLocalsNoTeeNoStructurePass() { + return new SimplifyLocals(false, false); } } // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index d5dc35718..4dc21ace0 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -91,6 +91,9 @@ void PassRegistry::registerPasses() { registerPass("reorder-functions", "sorts functions by access frequency", createReorderFunctionsPass); registerPass("reorder-locals", "sorts locals by access frequency", createReorderLocalsPass); registerPass("simplify-locals", "miscellaneous locals-related optimizations", createSimplifyLocalsPass); + registerPass("simplify-locals-notee", "miscellaneous locals-related optimizations", createSimplifyLocalsNoTeePass); + registerPass("simplify-locals-nostructure", "miscellaneous locals-related optimizations", createSimplifyLocalsNoStructurePass); + registerPass("simplify-locals-notee-nostructure", "miscellaneous locals-related optimizations", createSimplifyLocalsNoTeeNoStructurePass); registerPass("vacuum", "removes obviously unneeded code", createVacuumPass); registerPass("precompute", "computes compile-time evaluatable expressions", createPrecomputePass); // registerPass("lower-i64", "lowers i64 into pairs of i32s", createLowerInt64Pass); diff --git a/src/passes/passes.h b/src/passes/passes.h index c71831e73..98f99654e 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -51,6 +51,9 @@ Pass *createRemoveUnusedNamesPass(); Pass *createReorderFunctionsPass(); Pass *createReorderLocalsPass(); Pass *createSimplifyLocalsPass(); +Pass *createSimplifyLocalsNoTeePass(); +Pass *createSimplifyLocalsNoStructurePass(); +Pass *createSimplifyLocalsNoTeeNoStructurePass(); Pass *createVacuumPass(); Pass *createPrecomputePass(); //Pass *createLowerInt64Pass(); diff --git a/test/passes/simplify-locals-nostructure.txt b/test/passes/simplify-locals-nostructure.txt new file mode 100644 index 000000000..d2f050181 --- /dev/null +++ b/test/passes/simplify-locals-nostructure.txt @@ -0,0 +1,38 @@ +(module + (type $0 (func)) + (memory $0 0) + (func $contrast (type $0) + (local $x i32) + (local $y i32) + (local $z i32) + (nop) + (if + (tee_local $x + (i32.const 1) + ) + (nop) + ) + (if + (get_local $x) + (nop) + ) + (set_local $y + (if i32 + (i32.const 2) + (i32.const 3) + (i32.const 4) + ) + ) + (drop + (get_local $y) + ) + (set_local $z + (block $block i32 + (i32.const 5) + ) + ) + (drop + (get_local $z) + ) + ) +) diff --git a/test/passes/simplify-locals-nostructure.wast b/test/passes/simplify-locals-nostructure.wast new file mode 100644 index 000000000..fb938b8c5 --- /dev/null +++ b/test/passes/simplify-locals-nostructure.wast @@ -0,0 +1,15 @@ +(module + (func $contrast ;; check for tee and structure sinking + (local $x i32) + (local $y i32) + (local $z i32) + (set_local $x (i32.const 1)) + (if (get_local $x) (nop)) + (if (get_local $x) (nop)) + (set_local $y (if i32 (i32.const 2) (i32.const 3) (i32.const 4))) + (drop (get_local $y)) + (set_local $z (block i32 (i32.const 5))) + (drop (get_local $z)) + ) +) + diff --git a/test/passes/simplify-locals-notee-nostructure.txt b/test/passes/simplify-locals-notee-nostructure.txt new file mode 100644 index 000000000..8c948dba0 --- /dev/null +++ b/test/passes/simplify-locals-notee-nostructure.txt @@ -0,0 +1,38 @@ +(module + (type $0 (func)) + (memory $0 0) + (func $contrast (type $0) + (local $x i32) + (local $y i32) + (local $z i32) + (set_local $x + (i32.const 1) + ) + (if + (get_local $x) + (nop) + ) + (if + (get_local $x) + (nop) + ) + (set_local $y + (if i32 + (i32.const 2) + (i32.const 3) + (i32.const 4) + ) + ) + (drop + (get_local $y) + ) + (set_local $z + (block $block i32 + (i32.const 5) + ) + ) + (drop + (get_local $z) + ) + ) +) diff --git a/test/passes/simplify-locals-notee-nostructure.wast b/test/passes/simplify-locals-notee-nostructure.wast new file mode 100644 index 000000000..fb938b8c5 --- /dev/null +++ b/test/passes/simplify-locals-notee-nostructure.wast @@ -0,0 +1,15 @@ +(module + (func $contrast ;; check for tee and structure sinking + (local $x i32) + (local $y i32) + (local $z i32) + (set_local $x (i32.const 1)) + (if (get_local $x) (nop)) + (if (get_local $x) (nop)) + (set_local $y (if i32 (i32.const 2) (i32.const 3) (i32.const 4))) + (drop (get_local $y)) + (set_local $z (block i32 (i32.const 5))) + (drop (get_local $z)) + ) +) + diff --git a/test/passes/simplify-locals-notee.txt b/test/passes/simplify-locals-notee.txt new file mode 100644 index 000000000..7d8967c5f --- /dev/null +++ b/test/passes/simplify-locals-notee.txt @@ -0,0 +1,34 @@ +(module + (type $0 (func)) + (memory $0 0) + (func $contrast (type $0) + (local $x i32) + (local $y i32) + (local $z i32) + (set_local $x + (i32.const 1) + ) + (if + (get_local $x) + (nop) + ) + (if + (get_local $x) + (nop) + ) + (nop) + (drop + (if i32 + (i32.const 2) + (i32.const 3) + (i32.const 4) + ) + ) + (nop) + (drop + (block $block i32 + (i32.const 5) + ) + ) + ) +) diff --git a/test/passes/simplify-locals-notee.wast b/test/passes/simplify-locals-notee.wast new file mode 100644 index 000000000..fb938b8c5 --- /dev/null +++ b/test/passes/simplify-locals-notee.wast @@ -0,0 +1,15 @@ +(module + (func $contrast ;; check for tee and structure sinking + (local $x i32) + (local $y i32) + (local $z i32) + (set_local $x (i32.const 1)) + (if (get_local $x) (nop)) + (if (get_local $x) (nop)) + (set_local $y (if i32 (i32.const 2) (i32.const 3) (i32.const 4))) + (drop (get_local $y)) + (set_local $z (block i32 (i32.const 5))) + (drop (get_local $z)) + ) +) + diff --git a/test/passes/simplify-locals.txt b/test/passes/simplify-locals.txt index 36424193b..9175b3565 100644 --- a/test/passes/simplify-locals.txt +++ b/test/passes/simplify-locals.txt @@ -15,6 +15,36 @@ (import "env" "moddi" (func $___udivmoddi4 (param i32 i32 i32 i32 i32) (result i32))) (import "env" "lp" (func $lp (param i32 i32) (result i32))) (memory $0 256 256) + (func $contrast (type $FUNCSIG$v) + (local $x i32) + (local $y i32) + (local $z i32) + (nop) + (if + (tee_local $x + (i32.const 1) + ) + (nop) + ) + (if + (get_local $x) + (nop) + ) + (nop) + (drop + (if i32 + (i32.const 2) + (i32.const 3) + (i32.const 4) + ) + ) + (nop) + (drop + (block $block i32 + (i32.const 5) + ) + ) + ) (func $b0-yes (type $4) (param $i1 i32) (local $x i32) (local $y i32) diff --git a/test/passes/simplify-locals.wast b/test/passes/simplify-locals.wast index 06907a570..7f02a57c5 100644 --- a/test/passes/simplify-locals.wast +++ b/test/passes/simplify-locals.wast @@ -12,6 +12,18 @@ (import $_i64Subtract "env" "i64sub" (param i32 i32 i32 i32) (result i32)) (import $___udivmoddi4 "env" "moddi" (param i32 i32 i32 i32 i32) (result i32)) (import $lp "env" "lp" (param i32 i32) (result i32)) + (func $contrast ;; check for tee and structure sinking + (local $x i32) + (local $y i32) + (local $z i32) + (set_local $x (i32.const 1)) + (if (get_local $x) (nop)) + (if (get_local $x) (nop)) + (set_local $y (if i32 (i32.const 2) (i32.const 3) (i32.const 4))) + (drop (get_local $y)) + (set_local $z (block i32 (i32.const 5))) + (drop (get_local $z)) + ) (func $b0-yes (type $4) (param $i1 i32) (local $x i32) (local $y i32) |