summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-ssa.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-ir-ssa.cpp')
-rw-r--r--source/slang/slang-ir-ssa.cpp167
1 files changed, 102 insertions, 65 deletions
diff --git a/source/slang/slang-ir-ssa.cpp b/source/slang/slang-ir-ssa.cpp
index 08a5ffa67..19f85eaa9 100644
--- a/source/slang/slang-ir-ssa.cpp
+++ b/source/slang/slang-ir-ssa.cpp
@@ -891,63 +891,127 @@ void processBlock(
}
}
-static void breakCriticalEdges(
- ConstructSSAContext* context)
+IRBlock* IREdge::getPredecessor() const
+{
+ return cast<IRBlock>(getUse()->getUser()->parent);
+}
+
+IRBlock* IREdge::getSuccessor() const
+{
+ return cast<IRBlock>(getUse()->get());
+}
+
+void SharedIRBuilder::insertBlockAlongEdge(
+ IREdge const& edge)
+{
+ auto pred = edge.getPredecessor();
+ auto succ = edge.getSuccessor();
+ auto edgeUse = edge.getUse();
+
+ IRBuilder builder;
+ builder.sharedBuilder = this;
+ builder.setInsertInto(pred);
+
+ // Create a new block that will sit "along" the edge
+ IRBlock* edgeBlock = builder.createBlock();
+
+ edgeUse->debugValidate();
+
+ // The predecessor block should now branch to
+ // the edge block.
+ edgeUse->set(edgeBlock);
+
+ // The edge block should branch (unconditionally)
+ // to the successor block.
+ builder.setInsertInto(edgeBlock);
+ builder.emitBranch(succ);
+
+ // Insert the new block into the block list
+ // for the function.
+ //
+ // In principle, the order of this list shouldn't
+ // affect the semantics of a program, but we
+ // might want to be careful about ordering anyway.
+ edgeBlock->insertAfter(pred);
+}
+
+bool IREdge::isCritical() const
{
// A critical edge is an edge P -> S where
// P has multiple sucessors, and S has multiple
// predecessors.
//
- // In the context of our CFG representation, such an edge
- // will be an `IRUse` in the terminator instruction of block P,
- // which refers to block S.
+ auto pred = getPredecessor();
+ auto succ = getSuccessor();
+
+ // If the predecessor block doesn't have multiple successors,
+ // then this can't be a critical edge.
//
- // We will make a pass over the CFG to collect all the critical
- // edges, and then we will break them in a follow-up pass.
+ if(pred->getSuccessors().getCount() <= 1)
+ return false;
- List<IRUse*> criticalEdges;
+ // For the edge to be critical, the successor must have
+ // more than one predecessor.
+ //
+ // More than that, we require that it has more than one
+ // *unique* predecessor, to handle the case where multiple
+ // cases of a `switch` might lead to the same block.
+ //
+ // To implement this, we test if it has any predecessor
+ // other than `pred` which we already know about.
+ //
+ bool multiplePreds = false;
+ for (auto pp : succ->getPredecessors())
+ {
+ if (pp != pred)
+ {
+ multiplePreds = true;
+ break;
+ }
+ }
+ if(!multiplePreds)
+ return false;
+ // At this point we have confirmed that `edgeUse`
+ // leads from a block with multiple successors
+ // to one with multiple (distinct) predecessors,
+ // so we are sure it is a critical edge.
+ //
+ return true;
+}
+
+static void breakCriticalEdges(
+ ConstructSSAContext* context)
+{
auto globalVal = context->globalVal;
+
+ // We will make a pass over the CFG to collect all the critical
+ // edges, and then we will break them in a follow-up pass.
+ //
+ List<IREdge> criticalEdges;
for (auto pred = globalVal->getFirstBlock(); pred; pred = pred->getNextBlock())
{
+ // As an early out: if the predecessor block
+ // has one (or fewer) successors, then no
+ // edge from that block can be critical.
+ //
auto successors = pred->getSuccessors();
if (successors.getCount() <= 1)
continue;
+ // Otherwise, we iterate over its outgoing
+ // edges (represented with its successor list),
+ // and record those that are critical.
+ //
auto succIter = successors.begin();
auto succEnd = successors.end();
-
for (; succIter != succEnd; ++succIter)
{
- auto succ = *succIter;
-
- // For the edge to be critical, the successor must have
- // more than one predecessor.
- // More than that, we require that it has more than one
- // *unique* predecessor, to handle the case where multiple
- // cases of a `switch` might lead to the same block.
- //
- // To implement this, we test if it has any predecessor
- // other than `pred` which we already know about.
-
- bool multiplePreds = false;
- for (auto pp : succ->getPredecessors())
+ auto edge = succIter.getEdge();
+ if( edge.isCritical() )
{
- if (pp != pred)
- {
- multiplePreds = true;
- break;
- }
+ criticalEdges.add(edge);
}
- if (!multiplePreds)
- continue;
-
- // We have found a critical edge from `pred` to `succ`.
- //
- // Furthermore, the `IRUse` embedded in `succIter` represents
- // that edge directly.
- auto edgeUse = succIter.use;
- criticalEdges.add(edgeUse);
}
}
@@ -956,36 +1020,9 @@ static void breakCriticalEdges(
// to break the edges while doing the initial walk, because
// that would change the CFG while we are walking it.
- for (auto edgeUse : criticalEdges)
+ for (auto edge : criticalEdges)
{
- auto pred = cast<IRBlock>(edgeUse->getUser()->parent);
- auto succ = cast<IRBlock>(edgeUse->get());
-
- IRBuilder builder;
- builder.sharedBuilder = &context->sharedBuilder;
- builder.setInsertInto(pred);
-
- // Create a new block that will sit "along" the edge
- IRBlock* edgeBlock = builder.createBlock();
-
- edgeUse->debugValidate();
-
- // The predecessor block should now branch to
- // the edge block.
- edgeUse->set(edgeBlock);
-
- // The edge block should branch (unconditionally)
- // to the successor block.
- builder.setInsertInto(edgeBlock);
- builder.emitBranch(succ);
-
- // Insert the new block into the block list
- // for the function.
- //
- // In principle, the order of this list shouldn't
- // affect the semantics of a program, but we
- // might want to be careful about ordering anyway.
- edgeBlock->insertAfter(pred);
+ context->sharedBuilder.insertBlockAlongEdge(edge);
}
}