summaryrefslogtreecommitdiff
path: root/src/cfg/cfg-traversal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/cfg/cfg-traversal.h')
-rw-r--r--src/cfg/cfg-traversal.h33
1 files changed, 26 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) {