summaryrefslogtreecommitdiff
path: root/src/passes
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes')
-rw-r--r--src/passes/CoalesceLocals.cpp12
-rw-r--r--src/passes/DeadCodeElimination.cpp21
-rw-r--r--src/passes/MergeBlocks.cpp19
-rw-r--r--src/passes/Print.cpp16
-rw-r--r--src/passes/SimplifyLocals.cpp42
-rw-r--r--src/passes/Vacuum.cpp8
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);
}