summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cfg/cfg-traversal.h33
-rw-r--r--src/ir/LocalGraph.cpp4
-rw-r--r--src/passes/CoalesceLocals.cpp4
-rw-r--r--src/passes/RedundantSetElimination.cpp4
4 files changed, 38 insertions, 7 deletions
diff --git a/src/cfg/cfg-traversal.h b/src/cfg/cfg-traversal.h
index 42f7f168a..4ae075049 100644
--- a/src/cfg/cfg-traversal.h
+++ b/src/cfg/cfg-traversal.h
@@ -293,15 +293,34 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
}
}
+ // We can optionally ignore branches to outside of the function. Such a branch
+ // does not link two basic blocks (since the target is outside of the
+ // function), but it can cause us to end the current basic block and link to a
+ // new one, just in order to preserve the property that blocks do not have
+ // instructions in the middle that can transfer control flow somewhere. That
+ // property is useful to have in general, but if a user of this code just does
+ // not care about what happens when we leave the current function (say, if it
+ // only reads locals, which are gone anyhow if we leave) then it can flip this
+ // option to avoid creating new blocks just for such branches.
+ //
+ // The main situation where this matters is calls, which can throw if EH is
+ // enabled. With this set to ignore, we don't create new basic blocks just
+ // because of that, which can save a significant amount of overhead (~10%).
+ bool ignoreBranchesOutsideOfFunc = false;
+
static void doEndCall(SubType* self, Expression** currp) {
doEndThrowingInst(self, currp);
- // Create a new basic block and link to it. We do this even if there are no
- // other edges leaving this call (no catch bodies in this function that we
- // can reach if we throw), because we want to preserve the property that a
- // basic block ends with an instruction that might branch, and the call
- // might branch out of the entire function if it throws.
- auto* last = self->currBasicBlock;
- self->link(last, self->startBasicBlock());
+ if (!self->throwingInstsStack.empty() ||
+ !self->ignoreBranchesOutsideOfFunc) {
+ // |doEndThrowingInst| added a link from the current block to a catch, so
+ // we must end the current block and start another. Or, we are not
+ // ignoring branches to outside of the function, so even without a branch
+ // to a catch we want to start a new basic block here, to preserve the
+ // property that control flow transfers (both within the function or to
+ // the outside) can only happen at the end of basic blocks.
+ auto* last = self->currBasicBlock;
+ self->link(last, self->startBasicBlock());
+ }
}
static void doStartTry(SubType* self, Expression** currp) {
diff --git a/src/ir/LocalGraph.cpp b/src/ir/LocalGraph.cpp
index ab8ce16ba..af3a71d1f 100644
--- a/src/ir/LocalGraph.cpp
+++ b/src/ir/LocalGraph.cpp
@@ -54,6 +54,10 @@ struct Flower : public CFGWalker<Flower, Visitor<Flower>, Info> {
BasicBlock* makeBasicBlock() { return new BasicBlock(); }
+ // Branches outside of the function can be ignored, as we only look at locals
+ // which vanish when we leave.
+ bool ignoreBranchesOutsideOfFunc = true;
+
// cfg traversal work
static void doVisitLocalGet(Flower* self, Expression** currp) {
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index ce36b3c69..eb3babeb0 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -55,6 +55,10 @@ struct CoalesceLocals
return std::make_unique<CoalesceLocals>();
}
+ // Branches outside of the function can be ignored, as we only look at locals
+ // which vanish when we leave.
+ bool ignoreBranchesOutsideOfFunc = true;
+
// main entry point
void doWalkFunction(Function* func);
diff --git a/src/passes/RedundantSetElimination.cpp b/src/passes/RedundantSetElimination.cpp
index 4f82d5181..d54863639 100644
--- a/src/passes/RedundantSetElimination.cpp
+++ b/src/passes/RedundantSetElimination.cpp
@@ -68,6 +68,10 @@ struct RedundantSetElimination
return std::make_unique<RedundantSetElimination>();
}
+ // Branches outside of the function can be ignored, as we only look at locals
+ // which vanish when we leave.
+ bool ignoreBranchesOutsideOfFunc = true;
+
Index numLocals;
// In rare cases we make a change to a type that requires a refinalize.