diff options
Diffstat (limited to 'src/passes')
-rw-r--r-- | src/passes/CoalesceLocals.cpp | 12 | ||||
-rw-r--r-- | src/passes/DeadCodeElimination.cpp | 21 | ||||
-rw-r--r-- | src/passes/MergeBlocks.cpp | 19 | ||||
-rw-r--r-- | src/passes/Print.cpp | 16 | ||||
-rw-r--r-- | src/passes/SimplifyLocals.cpp | 42 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 8 |
6 files changed, 96 insertions, 22 deletions
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp index 2c707b614..2063a20db 100644 --- a/src/passes/CoalesceLocals.cpp +++ b/src/passes/CoalesceLocals.cpp @@ -485,9 +485,19 @@ void CoalesceLocals::applyIndices(std::vector<Index>& indices, Expression* root) // in addition, we can optimize out redundant copies and ineffective sets GetLocal* get; if ((get = set->value->dynCast<GetLocal>()) && get->index == set->index) { - *action.origin = get; // further optimizations may get rid of the get, if this is in a place where the output does not matter + if (set->isTee()) { + *action.origin = get; + } else { + ExpressionManipulator::nop(set); + } } else if (!action.effective) { *action.origin = set->value; // value may have no side effects, further optimizations can eliminate it + if (!set->isTee()) { + // we need to drop it + Drop* drop = ExpressionManipulator::convert<SetLocal, Drop>(set); + drop->value = *action.origin; + *action.origin = drop; + } } } } diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp index de1191131..aba442e71 100644 --- a/src/passes/DeadCodeElimination.cpp +++ b/src/passes/DeadCodeElimination.cpp @@ -31,6 +31,7 @@ #include <wasm.h> #include <pass.h> #include <ast_utils.h> +#include <wasm-builder.h> namespace wasm { @@ -191,6 +192,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V case Expression::Id::UnaryId: DELEGATE(Unary); case Expression::Id::BinaryId: DELEGATE(Binary); case Expression::Id::SelectId: DELEGATE(Select); + case Expression::Id::DropId: DELEGATE(Drop); case Expression::Id::ReturnId: DELEGATE(Return); case Expression::Id::HostId: DELEGATE(Host); case Expression::Id::NopId: DELEGATE(Nop); @@ -226,6 +228,11 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V // other things + Expression* drop(Expression* toDrop) { + if (toDrop->is<Unreachable>()) return toDrop; + return Builder(*getModule()).makeDrop(toDrop); + } + template<typename T> void handleCall(T* curr, Expression* initial) { for (Index i = 0; i < curr->operands.size(); i++) { @@ -236,11 +243,11 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V block->list.resize(newSize); Index j = 0; if (initial) { - block->list[j] = initial; + block->list[j] = drop(initial); j++; } for (; j < newSize; j++) { - block->list[j] = curr->operands[j - (initial ? 1 : 0)]; + block->list[j] = drop(curr->operands[j - (initial ? 1 : 0)]); } block->finalize(); replaceCurrent(block); @@ -288,7 +295,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V if (isDead(curr->value)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(2); - block->list[0] = curr->ptr; + block->list[0] = drop(curr->ptr); block->list[1] = curr->value; block->finalize(); replaceCurrent(block); @@ -309,7 +316,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V if (isDead(curr->right)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(2); - block->list[0] = curr->left; + block->list[0] = drop(curr->left); block->list[1] = curr->right; block->finalize(); replaceCurrent(block); @@ -324,7 +331,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V if (isDead(curr->ifFalse)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(2); - block->list[0] = curr->ifTrue; + block->list[0] = drop(curr->ifTrue); block->list[1] = curr->ifFalse; block->finalize(); replaceCurrent(block); @@ -333,8 +340,8 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination, V if (isDead(curr->condition)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(3); - block->list[0] = curr->ifTrue; - block->list[1] = curr->ifFalse; + block->list[0] = drop(curr->ifTrue); + block->list[1] = drop(curr->ifFalse); block->list[2] = curr->condition; block->finalize(); replaceCurrent(block); diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp index 686bb5d75..4798ad28d 100644 --- a/src/passes/MergeBlocks.cpp +++ b/src/passes/MergeBlocks.cpp @@ -74,10 +74,27 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks, Visitor<MergeBloc void visitBlock(Block *curr) { bool more = true; + bool changed = false; while (more) { more = false; for (size_t i = 0; i < curr->list.size(); i++) { Block* child = curr->list[i]->dynCast<Block>(); + if (!child) { + // TODO: if we have a child that is (drop (block ..)) then we can move the drop into the block, allowing more merging, + // but we must also drop values from brs + /* + auto* drop = curr->list[i]->dynCast<Drop>(); + if (drop) { + child = drop->value->dynCast<Block>(); + if (child) { + // reuse the drop + drop->value = child->list.back(); + child->list.back() = drop; + curr->list[i] = child; + } + } + */ + } if (!child) continue; if (child->name.is()) continue; // named blocks can have breaks to them (and certainly do, if we ran RemoveUnusedNames and RemoveUnusedBrs) ExpressionList merged(getModule()->allocator); @@ -92,9 +109,11 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks, Visitor<MergeBloc } curr->list = merged; more = true; + changed = true; break; } } + if (changed) curr->finalize(); } Block* optimize(Expression* curr, Expression*& child, Block* outer = nullptr, Expression** dependency1 = nullptr, Expression** dependency2 = nullptr) { diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 7486e07f1..ac349abc7 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -240,7 +240,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> { printOpening(o, "get_local ") << printableLocal(curr->index) << ')'; } void visitSetLocal(SetLocal *curr) { - printOpening(o, "set_local ") << printableLocal(curr->index); + if (curr->isTee()) { + printOpening(o, "tee_local "); + } else { + printOpening(o, "set_local "); + } + o << printableLocal(curr->index); incIndent(); printFullLine(curr->value); decIndent(); @@ -282,7 +287,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> { } void visitStore(Store *curr) { o << '('; - prepareColor(o) << printWasmType(curr->type) << ".store"; + prepareColor(o) << printWasmType(curr->valueType) << ".store"; if (curr->bytes < 4 || (curr->type == i64 && curr->bytes < 8)) { if (curr->bytes == 1) { o << '8'; @@ -467,6 +472,13 @@ struct PrintSExpression : public Visitor<PrintSExpression> { printFullLine(curr->condition); decIndent(); } + void visitDrop(Drop *curr) { + o << '('; + prepareColor(o) << "drop"; + incIndent(); + printFullLine(curr->value); + decIndent(); + } void visitReturn(Return *curr) { printOpening(o, "return"); if (!curr->value || curr->value->is<Nop>()) { diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index d9786e62c..5315edac4 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp @@ -55,7 +55,13 @@ struct SetLocalRemover : public PostWalker<SetLocalRemover, Visitor<SetLocalRemo void visitSetLocal(SetLocal *curr) { if ((*numGetLocals)[curr->index] == 0) { - replaceCurrent(curr->value); + auto* value = curr->value; + if (curr->isTee()) { + replaceCurrent(value); + } else { + Drop* drop = ExpressionManipulator::convert<SetLocal, Drop>(curr); + drop->value = value; + } } } }; @@ -180,7 +186,10 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, auto found = sinkables.find(curr->index); if (found != sinkables.end()) { // sink it, and nop the origin - replaceCurrent(*found->second.item); + auto* set = (*found->second.item)->cast<SetLocal>(); + replaceCurrent(set); + assert(!set->isTee()); + set->setTee(true); // reuse the getlocal that is dying *found->second.item = curr; ExpressionManipulator::nop(curr); @@ -189,6 +198,16 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, } } + void visitDrop(Drop* curr) { + // collapse drop-tee into set, which can occur if a get was sunk into a tee + auto* set = curr->value->dynCast<SetLocal>(); + if (set) { + assert(set->isTee()); + set->setTee(false); + replaceCurrent(set); + } + } + void checkInvalidations(EffectAnalyzer& effects) { // TODO: this is O(bad) std::vector<Index> invalidated; @@ -225,7 +244,11 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, // store is dead, leave just the value auto found = self->sinkables.find(set->index); if (found != self->sinkables.end()) { - *found->second.item = (*found->second.item)->cast<SetLocal>()->value; + auto* previous = (*found->second.item)->cast<SetLocal>(); + assert(!previous->isTee()); + auto* previousValue = previous->value; + Drop* drop = ExpressionManipulator::convert<SetLocal, Drop>(previous); + drop->value = previousValue; self->sinkables.erase(found); self->anotherCycle = true; } @@ -236,15 +259,10 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, self->checkInvalidations(effects); } - if (set) { - // we may be a replacement for the current node, update the stack - self->expressionStack.pop_back(); - self->expressionStack.push_back(set); - if (!ExpressionAnalyzer::isResultUsed(self->expressionStack, self->getFunction())) { - Index index = set->index; - assert(self->sinkables.count(index) == 0); - self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp))); - } + if (set && !set->isTee()) { + Index index = set->index; + assert(self->sinkables.count(index) == 0); + self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp))); } self->expressionStack.pop_back(); diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index 0195427d7..1b0887181 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -41,6 +41,7 @@ struct Vacuum : public WalkerPass<PostWalker<Vacuum, Visitor<Vacuum>>> { case Expression::Id::BlockId: return curr; // not always needed, but handled in visitBlock() case Expression::Id::IfId: return curr; // not always needed, but handled in visitIf() case Expression::Id::LoopId: return curr; // not always needed, but handled in visitLoop() + case Expression::Id::DropId: return curr; // not always needed, but handled in visitDrop() case Expression::Id::BreakId: case Expression::Id::SwitchId: @@ -198,6 +199,13 @@ struct Vacuum : public WalkerPass<PostWalker<Vacuum, Visitor<Vacuum>>> { if (curr->body->is<Nop>()) ExpressionManipulator::nop(curr); } + void visitDrop(Drop* curr) { + // if the drop input has no side effects, it can be wiped out + if (!EffectAnalyzer(curr->value).hasSideEffects()) { + ExpressionManipulator::nop(curr); + } + } + static void visitPre(Vacuum* self, Expression** currp) { self->expressionStack.push_back(*currp); } |