diff options
-rw-r--r-- | src/cfg/cfg-traversal.h | 33 | ||||
-rw-r--r-- | src/ir/LocalGraph.cpp | 4 | ||||
-rw-r--r-- | src/passes/CoalesceLocals.cpp | 4 | ||||
-rw-r--r-- | src/passes/RedundantSetElimination.cpp | 4 |
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. |