summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/cost.h12
-rw-r--r--src/ir/properties.h30
-rw-r--r--src/passes/AvoidReinterprets.cpp29
-rw-r--r--src/passes/OptimizeInstructions.cpp20
-rw-r--r--src/passes/Precompute.cpp3
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);