diff options
author | Heejin Ahn <aheejin@gmail.com> | 2020-02-05 14:37:53 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-05 14:37:53 -0800 |
commit | 7be22c4d68270573ee010938aa8cd06be89e54d2 (patch) | |
tree | ef9607bef85aabb344234484818ffc29f2235919 /src | |
parent | 33f92aa06fe5de7bcf9f6b7fe2e74ba5e8e1e782 (diff) | |
download | binaryen-7be22c4d68270573ee010938aa8cd06be89e54d2.tar.gz binaryen-7be22c4d68270573ee010938aa8cd06be89e54d2.tar.bz2 binaryen-7be22c4d68270573ee010938aa8cd06be89e54d2.zip |
Add EH support for OptimizeInstructions (#2608)
- Adds support for `Try` in `optimizeBoolean` function
- Adds support for `Try` in `getFallThrough` function
- Adds approximate cost values for instructions in EH and reference
types proposals.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/cost.h | 12 | ||||
-rw-r--r-- | src/ir/properties.h | 30 | ||||
-rw-r--r-- | src/passes/AvoidReinterprets.cpp | 29 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 20 | ||||
-rw-r--r-- | src/passes/Precompute.cpp | 3 |
5 files changed, 69 insertions, 25 deletions
diff --git a/src/ir/cost.h b/src/ir/cost.h index 37f2611dd..e89fb9d17 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -726,6 +726,18 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> { Index visitDrop(Drop* curr) { return visit(curr->value); } Index visitReturn(Return* curr) { return maybeVisit(curr->value); } Index visitHost(Host* curr) { return 100; } + Index visitRefNull(RefNull* curr) { return 1; } + Index visitRefIsNull(RefIsNull* curr) { return 1; } + Index visitRefFunc(RefFunc* curr) { return 1; } + Index visitTry(Try* curr) { + // We assume no exception will be thrown in most cases + return visit(curr->body); + } + Index visitThrow(Throw* curr) { return 100; } + Index visitRethrow(Rethrow* curr) { return 100; } + Index visitBrOnExn(BrOnExn* curr) { + return 1 + visit(curr->exnref) + curr->sent.size(); + } Index visitNop(Nop* curr) { return 0; } Index visitUnreachable(Unreachable* curr) { return 0; } }; diff --git a/src/ir/properties.h b/src/ir/properties.h index 01e78563d..1dbb0e096 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -18,6 +18,8 @@ #define wasm_ir_properties_h #include "ir/bits.h" +#include "ir/effects.h" +#include "ir/iteration.h" #include "wasm.h" namespace wasm { @@ -68,6 +70,10 @@ inline bool isNamedControlFlow(Expression* curr) { return false; } +inline bool isConstantExpression(const Expression* curr) { + return curr->is<Const>() || curr->is<RefNull>() || curr->is<RefFunc>(); +} + // Check if an expression is a sign-extend, and if so, returns the value // that is extended, otherwise nullptr inline Expression* getSignExtValue(Expression* curr) { @@ -153,7 +159,9 @@ inline Index getZeroExtBits(Expression* curr) { // Returns a falling-through value, that is, it looks through a local.tee // and other operations that receive a value and let it flow through them. -inline Expression* getFallthrough(Expression* curr) { +inline Expression* getFallthrough(Expression* curr, + const PassOptions& passOptions, + FeatureSet features) { // If the current node is unreachable, there is no value // falling through. if (curr->type == Type::unreachable) { @@ -161,36 +169,36 @@ inline Expression* getFallthrough(Expression* curr) { } if (auto* set = curr->dynCast<LocalSet>()) { if (set->isTee()) { - return getFallthrough(set->value); + return getFallthrough(set->value, passOptions, features); } } else if (auto* block = curr->dynCast<Block>()) { // if no name, we can't be broken to, and then can look at the fallthrough if (!block->name.is() && block->list.size() > 0) { - return getFallthrough(block->list.back()); + return getFallthrough(block->list.back(), passOptions, features); } } else if (auto* loop = curr->dynCast<Loop>()) { - return getFallthrough(loop->body); + return getFallthrough(loop->body, passOptions, features); } else if (auto* iff = curr->dynCast<If>()) { if (iff->ifFalse) { // Perhaps just one of the two actually returns. if (iff->ifTrue->type == Type::unreachable) { - return getFallthrough(iff->ifFalse); + return getFallthrough(iff->ifFalse, passOptions, features); } else if (iff->ifFalse->type == Type::unreachable) { - return getFallthrough(iff->ifTrue); + return getFallthrough(iff->ifTrue, passOptions, features); } } } else if (auto* br = curr->dynCast<Break>()) { if (br->condition && br->value) { - return getFallthrough(br->value); + return getFallthrough(br->value, passOptions, features); + } + } else if (auto* tryy = curr->dynCast<Try>()) { + if (!EffectAnalyzer(passOptions, features, tryy->body).throws) { + return getFallthrough(tryy->body, passOptions, features); } } return curr; } -inline bool isConstantExpression(const Expression* curr) { - return curr->is<Const>() || curr->is<RefNull>() || curr->is<RefFunc>(); -} - } // namespace Properties } // namespace wasm diff --git a/src/passes/AvoidReinterprets.cpp b/src/passes/AvoidReinterprets.cpp index 4df75dd15..91a20912d 100644 --- a/src/passes/AvoidReinterprets.cpp +++ b/src/passes/AvoidReinterprets.cpp @@ -36,7 +36,10 @@ static bool canReplaceWithReinterpret(Load* load) { load->bytes == load->type.getByteSize(); } -static Load* getSingleLoad(LocalGraph* localGraph, LocalGet* get) { +static Load* getSingleLoad(LocalGraph* localGraph, + LocalGet* get, + const PassOptions& passOptions, + FeatureSet features) { std::set<LocalGet*> seen; seen.insert(get); while (1) { @@ -48,7 +51,7 @@ static Load* getSingleLoad(LocalGraph* localGraph, LocalGet* get) { if (!set) { return nullptr; } - auto* value = Properties::getFallthrough(set->value); + auto* value = Properties::getFallthrough(set->value, passOptions, features); if (auto* parentGet = value->dynCast<LocalGet>()) { if (seen.count(parentGet)) { // We are in a cycle of gets, in unreachable code. @@ -98,9 +101,12 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> { void visitUnary(Unary* curr) { if (isReinterpret(curr)) { + FeatureSet features = getModule()->features; if (auto* get = - Properties::getFallthrough(curr->value)->dynCast<LocalGet>()) { - if (auto* load = getSingleLoad(localGraph, get)) { + Properties::getFallthrough(curr->value, getPassOptions(), features) + ->dynCast<LocalGet>()) { + if (auto* load = + getSingleLoad(localGraph, get, getPassOptions(), features)) { auto& info = infos[load]; info.reinterpreted = true; } @@ -130,22 +136,27 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> { std::map<Load*, Info>& infos; LocalGraph* localGraph; Module* module; + const PassOptions& passOptions; FinalOptimizer(std::map<Load*, Info>& infos, LocalGraph* localGraph, - Module* module) - : infos(infos), localGraph(localGraph), module(module) {} + Module* module, + const PassOptions& passOptions) + : infos(infos), localGraph(localGraph), module(module), + passOptions(passOptions) {} void visitUnary(Unary* curr) { if (isReinterpret(curr)) { - auto* value = Properties::getFallthrough(curr->value); + auto* value = Properties::getFallthrough( + curr->value, passOptions, module->features); if (auto* load = value->dynCast<Load>()) { // A reinterpret of a load - flip it right here if we can. if (canReplaceWithReinterpret(load)) { replaceCurrent(makeReinterpretedLoad(load, load->ptr)); } } else if (auto* get = value->dynCast<LocalGet>()) { - if (auto* load = getSingleLoad(localGraph, get)) { + if (auto* load = getSingleLoad( + localGraph, get, passOptions, module->features)) { auto iter = infos.find(load); if (iter != infos.end()) { auto& info = iter->second; @@ -188,7 +199,7 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> { ptr, load->type.reinterpret()); } - } finalOptimizer(infos, localGraph, getModule()); + } finalOptimizer(infos, localGraph, getModule(), getPassOptions()); finalOptimizer.walk(func->body); } diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 90abed825..3e3863e95 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -200,8 +200,11 @@ struct LocalInfo { struct LocalScanner : PostWalker<LocalScanner> { std::vector<LocalInfo>& localInfo; + const PassOptions& passOptions; - LocalScanner(std::vector<LocalInfo>& localInfo) : localInfo(localInfo) {} + LocalScanner(std::vector<LocalInfo>& localInfo, + const PassOptions& passOptions) + : localInfo(localInfo), passOptions(passOptions) {} void doWalkFunction(Function* func) { // prepare @@ -236,7 +239,8 @@ struct LocalScanner : PostWalker<LocalScanner> { return; } // an integer var, worth processing - auto* value = Properties::getFallthrough(curr->value); + auto* value = Properties::getFallthrough( + curr->value, passOptions, getModule()->features); auto& info = localInfo[curr->index]; info.maxBits = std::max(info.maxBits, getMaxBits(value, this)); auto signExtBits = LocalInfo::kUnknown; @@ -289,7 +293,8 @@ struct OptimizeInstructions void doWalkFunction(Function* func) { // first, scan locals { - LocalScanner scanner(localInfo); + LocalScanner scanner(localInfo, getPassOptions()); + scanner.setModule(getModule()); scanner.walkFunction(func); } // main walk @@ -347,7 +352,9 @@ struct OptimizeInstructions Index extraShifts; auto bits = Properties::getAlmostSignExtBits(binary, extraShifts); if (extraShifts == 0) { - if (auto* load = Properties::getFallthrough(ext)->dynCast<Load>()) { + if (auto* load = + Properties::getFallthrough(ext, getPassOptions(), features) + ->dynCast<Load>()) { // pattern match a load of 8 bits and a sign extend using a shl of // 24 then shr_s of 24 as well, etc. if (LoadUtils::canBeSigned(load) && @@ -984,6 +991,11 @@ private: } else if (auto* select = boolean->dynCast<Select>()) { select->ifTrue = optimizeBoolean(select->ifTrue); select->ifFalse = optimizeBoolean(select->ifFalse); + } else if (auto* tryy = boolean->dynCast<Try>()) { + if (tryy->type == Type::i32) { + tryy->body = optimizeBoolean(tryy->body); + tryy->catchBody = optimizeBoolean(tryy->catchBody); + } } // TODO: recurse into br values? return boolean; diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 21393c1cf..3a886166c 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -327,7 +327,8 @@ private: continue; // already known constant } auto value = setValues[set] = - precomputeValue(Properties::getFallthrough(set->value)); + precomputeValue(Properties::getFallthrough( + set->value, getPassOptions(), getModule()->features)); if (value.isConcrete()) { for (auto* get : localGraph.setInfluences[set]) { work.insert(get); |