summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ir-propagate-func-properties.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2023-02-24 10:01:47 -0800
committerGitHub <noreply@github.com>2023-02-24 10:01:47 -0800
commitbd6306cdaa4a49344658bd026721b6532e103d09 (patch)
treebb7f666d426e6cfc7777a3ccac0a1d628588eb39 /source/slang/slang-ir-propagate-func-properties.cpp
parente8c08e7ecb1124f115a1d1042277776193122b57 (diff)
More control flow simplifications. (#2673)
* More control flow and Phi param simplifications. * Fix. * Fix gcc error. * Fix. * More IR cleanup. * Fix bug in phi param dce + ifelse simplify. * Propagate and DCE side-effect-free functions. * Enhance CFG simplifcation to remove loops with no side effects. * Fix. * Fixes. * Fix tests. Add [__AlwaysFoldIntoUseSite] for rayPayloadLocation. * More cleanup. * Fixes. * Fix. --------- Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source/slang/slang-ir-propagate-func-properties.cpp')
-rw-r--r--source/slang/slang-ir-propagate-func-properties.cpp186
1 files changed, 186 insertions, 0 deletions
diff --git a/source/slang/slang-ir-propagate-func-properties.cpp b/source/slang/slang-ir-propagate-func-properties.cpp
new file mode 100644
index 000000000..f98a77fc7
--- /dev/null
+++ b/source/slang/slang-ir-propagate-func-properties.cpp
@@ -0,0 +1,186 @@
+#include "slang-ir-propagate-func-properties.h"
+
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+#include "slang-ir-util.h"
+
+
+namespace Slang
+{
+bool propagateFuncProperties(IRModule* module)
+{
+ bool result = false;
+ List<IRFunc*> workList;
+ HashSet<IRFunc*> workListSet;
+
+ auto addToWorkList = [&](IRFunc* f)
+ {
+ if (workListSet.Add(f))
+ workList.add(f);
+ };
+ auto addCallersToWorkList = [&](IRFunc* f)
+ {
+ if (auto g = findOuterGeneric(f))
+ {
+ for (auto use = g->firstUse; use; use = use->nextUse)
+ {
+ if (use->getUser()->getOp() == kIROp_Specialize)
+ {
+ auto specialize = use->getUser();
+ for (auto iuse = specialize->firstUse; iuse; iuse = iuse->nextUse)
+ {
+ if (auto userFunc = getParentFunc(iuse->getUser()))
+ addToWorkList(userFunc);
+ }
+ }
+ }
+ return;
+ }
+ for (auto use = f->firstUse; use; use = use->nextUse)
+ {
+ if (use->getUser()->getOp() == kIROp_Call)
+ {
+ if (auto userFunc = getParentFunc(use->getUser()))
+ addToWorkList(userFunc);
+ }
+ }
+ };
+ for (;;)
+ {
+ bool changed = false;
+ workList.clear();
+ workListSet.Clear();
+
+ // Add side effect free functions and their transitive callers to work list.
+ for (auto inst : module->getGlobalInsts())
+ {
+ auto genericInst = as<IRGeneric>(inst);
+ if (genericInst)
+ {
+ inst = findGenericReturnVal(genericInst);
+ }
+ if (auto func = as<IRFunc>(inst))
+ {
+ if (func->findDecoration<IRReadNoneDecoration>())
+ {
+ addCallersToWorkList(func);
+ }
+ }
+ }
+
+ // Add remaining functions to work list.
+ for (auto inst : module->getGlobalInsts())
+ {
+ auto genericInst = as<IRGeneric>(inst);
+ if (genericInst)
+ {
+ inst = findGenericReturnVal(genericInst);
+ }
+ if (auto func = as<IRFunc>(inst))
+ {
+ addToWorkList(func);
+ }
+ }
+
+ IRBuilder builder(module);
+
+ for (Index i = 0; i < workList.getCount(); i++)
+ {
+ auto f = workList[i];
+ bool hasSideEffectCall = false;
+ if (f->findDecoration<IRReadNoneDecoration>())
+ continue;
+ // Never propagate to functions without a body.
+ if (f->getFirstBlock() == nullptr)
+ continue;
+ if (f->findDecoration<IRTargetIntrinsicDecoration>())
+ continue;
+ for (auto block : f->getBlocks())
+ {
+ for (auto inst : block->getChildren())
+ {
+ // Is this inst known to not have global side effect/analyzable?
+ if (inst->mightHaveSideEffects())
+ {
+ switch (inst->getOp())
+ {
+ case kIROp_ifElse:
+ case kIROp_unconditionalBranch:
+ case kIROp_Switch:
+ case kIROp_Return:
+ case kIROp_loop:
+ case kIROp_Store:
+ case kIROp_Call:
+ case kIROp_Param:
+ case kIROp_Unreachable:
+ break;
+ default:
+ // We have a inst that has side effect and is not understood by this method.
+ // e.g. bufferStore, discard, etc.
+ return true;
+ }
+ }
+
+ if (auto call = as<IRCall>(inst))
+ {
+ auto callee = getResolvedInstForDecorations(call->getCallee());
+ switch (callee->getOp())
+ {
+ default:
+ // We are calling an unknown function, so we have to assume
+ // there are side effects in the call.
+ hasSideEffectCall = true;
+ break;
+ case kIROp_Func:
+ if (!callee->findDecoration<IRReadNoneDecoration>())
+ {
+ hasSideEffectCall = true;
+ break;
+ }
+ }
+ }
+
+ // Are any operands defined in global scope?
+ for (UInt o = 0; o < inst->getOperandCount(); o++)
+ {
+ auto operand = inst->getOperand(o);
+ if (getParentFunc(operand) == f)
+ continue;
+ if (as<IRConstant>(operand))
+ continue;
+ if (as<IRType>(operand))
+ continue;
+ switch (operand->getOp())
+ {
+ case kIROp_Specialize:
+ case kIROp_LookupWitness:
+ case kIROp_StructKey:
+ case kIROp_WitnessTable:
+ case kIROp_WitnessTableEntry:
+ case kIROp_undefined:
+ case kIROp_Func:
+ continue;
+ default:
+ break;
+ }
+ hasSideEffectCall = true;
+ break;
+ }
+ }
+ if (hasSideEffectCall)
+ break;
+ }
+ if (!hasSideEffectCall)
+ {
+ builder.addDecoration(f, kIROp_ReadNoneDecoration);
+ addCallersToWorkList(f);
+ changed = true;
+ }
+ }
+ result |= changed;
+ if (!changed)
+ break;
+ }
+ return result;
+}
+}