summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ir-util.cpp
diff options
context:
space:
mode:
authorSai Praveen Bangaru <31557731+saipraveenb25@users.noreply.github.com>2025-01-20 14:30:56 -0500
committerGitHub <noreply@github.com>2025-01-20 14:30:56 -0500
commitb11c25749d29ff37fe1f3379746ceb614602e3fa (patch)
tree395b6c049b259796f5e2f65f7f07624d920619c3 /source/slang/slang-ir-util.cpp
parentf3d7aa6ce964e3f8e2550886dae24ee6cba7ae9c (diff)
Fix def-use issue from multi-level break elimination (#6134)
Diffstat (limited to 'source/slang/slang-ir-util.cpp')
-rw-r--r--source/slang/slang-ir-util.cpp107
1 files changed, 107 insertions, 0 deletions
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp
index d05e1db7d..3043e7e31 100644
--- a/source/slang/slang-ir-util.cpp
+++ b/source/slang/slang-ir-util.cpp
@@ -1986,4 +1986,111 @@ Int getSpecializationConstantId(IRGlobalParam* param)
return offset->getOffset();
}
+void legalizeDefUse(IRGlobalValueWithCode* func)
+{
+ auto dom = computeDominatorTree(func);
+ for (auto block : func->getBlocks())
+ {
+ for (auto inst : block->getModifiableChildren())
+ {
+ // Inspect all uses of `inst` and find the common dominator of all use sites.
+ IRBlock* commonDominator = block;
+ for (auto use = inst->firstUse; use; use = use->nextUse)
+ {
+ auto userBlock = as<IRBlock>(use->getUser()->getParent());
+ if (!userBlock)
+ continue;
+ while (commonDominator && !dom->dominates(commonDominator, userBlock))
+ {
+ commonDominator = dom->getImmediateDominator(commonDominator);
+ }
+ }
+ SLANG_ASSERT(commonDominator);
+
+ if (commonDominator == block)
+ continue;
+
+ // If the common dominator is not `block`, it means we have detected
+ // uses that is no longer dominated by the current definition, and need
+ // to be fixed.
+
+ // Normally, we can simply move the definition to the common dominator.
+ // An exception is when the common dominator is the target block of a
+ // loop. Note that after normalization, loops are in the form of:
+ // ```
+ // loop { if (condition) block; else break; }
+ // ```
+ // If we find ourselves needing to make the inst available right before
+ // the `if`, it means we are seeing uses of the inst outside the loop.
+ // In this case, we should insert a var/move the inst before the loop
+ // instead of before the `if`. This situation can occur in the IR if
+ // the original code is lowered from a `do-while` loop.
+ for (auto use = commonDominator->firstUse; use; use = use->nextUse)
+ {
+ if (auto loopUser = as<IRLoop>(use->getUser()))
+ {
+ if (loopUser->getTargetBlock() == commonDominator)
+ {
+ bool shouldMoveToHeader = false;
+ // Check that the break-block dominates any of the uses are past the break
+ // block
+ for (auto _use = inst->firstUse; _use; _use = _use->nextUse)
+ {
+ if (dom->dominates(
+ loopUser->getBreakBlock(),
+ _use->getUser()->getParent()))
+ {
+ shouldMoveToHeader = true;
+ break;
+ }
+ }
+
+ if (shouldMoveToHeader)
+ commonDominator = as<IRBlock>(loopUser->getParent());
+ break;
+ }
+ }
+ }
+ // Now we can legalize uses based on the type of `inst`.
+ if (auto var = as<IRVar>(inst))
+ {
+ // If inst is an var, this is easy, we just move it to the
+ // common dominator.
+ var->insertBefore(commonDominator->getTerminator());
+ }
+ else
+ {
+ // For all other insts, we need to create a local var for it,
+ // and replace all uses with a load from the local var.
+ IRBuilder builder(func);
+ builder.setInsertBefore(commonDominator->getTerminator());
+ IRVar* tempVar = builder.emitVar(inst->getFullType());
+ auto defaultVal = builder.emitDefaultConstruct(inst->getFullType());
+ builder.emitStore(tempVar, defaultVal);
+
+ builder.setInsertAfter(inst);
+ builder.emitStore(tempVar, inst);
+
+ traverseUses(
+ inst,
+ [&](IRUse* use)
+ {
+ auto userBlock = as<IRBlock>(use->getUser()->getParent());
+ if (!userBlock)
+ return;
+ // Only fix the use of the current definition of `inst` does not
+ // dominate it.
+ if (!dom->dominates(block, userBlock))
+ {
+ // Replace the use with a load of tempVar.
+ builder.setInsertBefore(use->getUser());
+ auto load = builder.emitLoad(tempVar);
+ builder.replaceOperand(use, load);
+ }
+ });
+ }
+ }
+ }
+}
+
} // namespace Slang