summaryrefslogtreecommitdiff
path: root/src/passes/Vacuum.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-09-14 21:28:43 -0700
committerGitHub <noreply@github.com>2016-09-14 21:28:43 -0700
commite567fa8675831e79f855cea2181fa58beb107e42 (patch)
tree14f1e37d27244b349e8ee34939119002f742748d /src/passes/Vacuum.cpp
parent63b499e3ec9bbdf4e79ab6d9dc198299516e8aec (diff)
parentaf3bea2786fe62070522b7fd7add4290a4cb4e6d (diff)
downloadbinaryen-e567fa8675831e79f855cea2181fa58beb107e42.tar.gz
binaryen-e567fa8675831e79f855cea2181fa58beb107e42.tar.bz2
binaryen-e567fa8675831e79f855cea2181fa58beb107e42.zip
Merge pull request #695 from WebAssembly/opts
Get optimizer on par with emscripten asm.js optimizer
Diffstat (limited to 'src/passes/Vacuum.cpp')
-rw-r--r--src/passes/Vacuum.cpp73
1 files changed, 62 insertions, 11 deletions
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index db42a994a..0fdd12dec 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -47,26 +47,31 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>>
case Expression::Id::CallImportId:
case Expression::Id::CallIndirectId:
case Expression::Id::SetLocalId:
- case Expression::Id::LoadId:
case Expression::Id::StoreId:
case Expression::Id::ReturnId:
- case Expression::Id::GetGlobalId:
case Expression::Id::SetGlobalId:
case Expression::Id::HostId:
case Expression::Id::UnreachableId: return curr; // always needed
+ case Expression::Id::LoadId: {
+ if (!resultUsed) {
+ return curr->cast<Load>()->ptr;
+ }
+ return curr;
+ }
case Expression::Id::ConstId:
case Expression::Id::GetLocalId:
+ case Expression::Id::GetGlobalId: {
+ if (!resultUsed) return nullptr;
+ return curr;
+ }
+
case Expression::Id::UnaryId:
case Expression::Id::BinaryId:
case Expression::Id::SelectId: {
if (resultUsed) {
return curr; // used, keep it
}
- // result is not used, perhaps it is dead
- if (curr->is<Const>() || curr->is<GetLocal>()) {
- return nullptr;
- }
// for unary, binary, and select, we need to check their arguments for side effects
if (auto* unary = curr->dynCast<Unary>()) {
if (EffectAnalyzer(unary->value).hasSideEffects()) {
@@ -132,13 +137,12 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>>
void visitBlock(Block *curr) {
// compress out nops and other dead code
- bool resultUsed = ExpressionAnalyzer::isResultUsed(expressionStack, getFunction());
int skip = 0;
auto& list = curr->list;
size_t size = list.size();
bool needResize = false;
for (size_t z = 0; z < size; z++) {
- auto* optimized = optimize(list[z], z == size - 1 && resultUsed);
+ auto* optimized = optimize(list[z], z == size - 1 && isConcreteWasmType(curr->type));
if (!optimized) {
skip++;
needResize = true;
@@ -153,7 +157,12 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>>
Break* br = list[z - skip]->dynCast<Break>();
Switch* sw = list[z - skip]->dynCast<Switch>();
if ((br && !br->condition) || sw) {
+ auto* last = list.back();
list.resize(z - skip + 1);
+ // if we removed the last one, and it was a return value, it must be returned
+ if (list.back() != last && isConcreteWasmType(last->type)) {
+ list.push_back(last);
+ }
needResize = false;
break;
}
@@ -165,7 +174,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>>
if (!curr->name.is()) {
if (list.size() == 1) {
// just one element. replace the block, either with it or with a nop if it's not needed
- if (resultUsed || EffectAnalyzer(list[0]).hasSideEffects()) {
+ if (isConcreteWasmType(curr->type) || EffectAnalyzer(list[0]).hasSideEffects()) {
replaceCurrent(list[0]);
} else {
ExpressionManipulator::nop(curr);
@@ -200,11 +209,53 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>>
}
void visitDrop(Drop* curr) {
- // if the drop input has no side effects, it can be wiped out
- if (!EffectAnalyzer(curr->value).hasSideEffects()) {
+ // optimize the dropped value, maybe leaving nothing
+ curr->value = optimize(curr->value, false);
+ if (curr->value == nullptr) {
ExpressionManipulator::nop(curr);
return;
}
+ // a drop of a tee is a set
+ if (auto* set = curr->value->dynCast<SetLocal>()) {
+ assert(set->isTee());
+ set->setTee(false);
+ replaceCurrent(set);
+ return;
+ }
+ // if we are dropping a block's return value, we might be able to remove it entirely
+ if (auto* block = curr->value->dynCast<Block>()) {
+ auto* last = block->list.back();
+ if (isConcreteWasmType(last->type)) {
+ assert(block->type == last->type);
+ last = optimize(last, false);
+ if (!last) {
+ // we may be able to remove this, if there are no brs
+ bool canPop = true;
+ if (block->name.is()) {
+ BreakSeeker breakSeeker(block->name);
+ Expression* temp = block;
+ breakSeeker.walk(temp);
+ if (breakSeeker.found && breakSeeker.valueType != none) {
+ canPop = false;
+ }
+ }
+ if (canPop) {
+ block->list.back() = last;
+ block->list.pop_back();
+ block->type = none;
+ // we don't need the drop anymore, let's see what we have left in the block
+ if (block->list.size() > 1) {
+ replaceCurrent(block);
+ } else if (block->list.size() == 1) {
+ replaceCurrent(block->list[0]);
+ } else {
+ ExpressionManipulator::nop(curr);
+ }
+ return;
+ }
+ }
+ }
+ }
// sink a drop into an arm of an if-else if the other arm ends in an unreachable, as it if is a branch, this can make that branch optimizable and more vaccuming possible
auto* iff = curr->value->dynCast<If>();
if (iff && iff->ifFalse && isConcreteWasmType(iff->type)) {