summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-simplify-cfg.cpp
diff options
context:
space:
mode:
authorSai Praveen Bangaru <31557731+saipraveenb25@users.noreply.github.com>2023-08-25 14:53:12 -0400
committerGitHub <noreply@github.com>2023-08-25 14:53:12 -0400
commit06f7ef354cdde4cf8e8797d8853ed2d9c3208b5b (patch)
tree43458d031c791b1e03b469f2b059391cf4a755b6 /source/slang/slang-ir-simplify-cfg.cpp
parentef4c9f1f1c297f1a33be95795a7a7561e0cc3bde (diff)
Fix various issues with trivial loops (#3149)
* Fix issue with trivial loop detection * Fix issue with unreachable blocks in break elimination Add logic to avoid eliminating loops with multi-level breaks. * Incorporate feedback - Use a boolean for multi-level break check - Use dominator trees for region check instead of exhaustive enumeration - Fix potential issue with enumerating parent break blocks. * fix
Diffstat (limited to 'source/slang/slang-ir-simplify-cfg.cpp')
-rw-r--r--source/slang/slang-ir-simplify-cfg.cpp71
1 files changed, 60 insertions, 11 deletions
diff --git a/source/slang/slang-ir-simplify-cfg.cpp b/source/slang/slang-ir-simplify-cfg.cpp
index e848d11c1..44a8909e4 100644
--- a/source/slang/slang-ir-simplify-cfg.cpp
+++ b/source/slang/slang-ir-simplify-cfg.cpp
@@ -29,6 +29,32 @@ static BreakableRegion* findBreakableRegion(Region* region)
}
}
+static bool isBlockInRegion(IRDominatorTree* domTree, IRTerminatorInst* regionHeader, IRBlock* block)
+{
+ auto headerBlock = cast<IRBlock>(regionHeader->getParent());
+ IRBlock* breakBlock = nullptr;
+ if (auto loop = as<IRLoop>(regionHeader))
+ breakBlock = loop->getBreakBlock();
+ else if (auto switchInst = as<IRSwitch>(regionHeader))
+ breakBlock = switchInst->getBreakLabel();
+
+ auto parentBreakBlocks = getParentBreakBlockSet(domTree, headerBlock);
+
+ if (!domTree->dominates(headerBlock, block))
+ return false;
+
+ if (domTree->dominates(breakBlock, block))
+ return false;
+
+ for (auto parentBreakBlock : parentBreakBlocks)
+ {
+ if (domTree->dominates(parentBreakBlock, block))
+ return false;
+ }
+
+ return true;
+}
+
// Test if a loop is trivial: a trivial loop runs for a single iteration without any back edges, and
// there is only one break out of the loop at the very end. The function generates `regionTree` if
// it is needed and hasn't been generated yet.
@@ -102,19 +128,36 @@ static bool isTrivialSingleIterationLoop(
// Track the break block backwards through the dominator tree, and see if we find a loop block
// that is not the current loop.
//
- auto currBlock = loop->getBreakBlock();
- for (;;)
+ auto breakPredList = loop->getBreakBlock()->getPredecessors();
+
+ if (breakPredList.getCount() > 0)
{
- auto parent = context.domTree->getImmediateDominator(currBlock);
- if (!parent)
- break;
- currBlock = parent;
- if (auto _loop = as<IRLoop>(currBlock->getTerminator()))
+ auto breakOriginBlock = *loop->getBreakBlock()->getPredecessors().begin();
+
+ for (auto currBlock = breakOriginBlock;
+ currBlock;
+ currBlock = context.domTree->getImmediateDominator(currBlock))
{
- if (loop != _loop)
- return false;
- if (loop == _loop)
+ auto terminator = currBlock->getTerminator();
+ if (terminator == loop)
+ break;
+
+ // Check if the break originated from an inner breakable region.
+ // If so, the outer loop cannot be trivially removed.
+ //
+ switch (terminator->getOp())
+ {
+ case kIROp_loop:
+ if (isBlockInRegion(context.domTree, as<IRLoop>(terminator), breakOriginBlock))
+ return false;
break;
+ case kIROp_Switch:
+ if (isBlockInRegion(context.domTree, as<IRSwitch>(terminator), breakOriginBlock))
+ return false;
+ break;
+ default:
+ break;
+ }
}
}
@@ -123,7 +166,13 @@ static bool isTrivialSingleIterationLoop(
static bool doesLoopHasSideEffect(IRGlobalValueWithCode* func, IRLoop* loopInst)
{
- auto blocks = collectBlocksInLoop(func, loopInst);
+ bool hasMultiLevelBreaks = false;
+ auto blocks = collectBlocksInRegion(func, loopInst, &hasMultiLevelBreaks);
+
+ // We'll currently not deal with loops that contain multi-level breaks.
+ if (hasMultiLevelBreaks)
+ return true;
+
HashSet<IRBlock*> loopBlocks;
for (auto b : blocks)
loopBlocks.add(b);