summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-dce.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2022-06-23 12:41:05 -0700
committerGitHub <noreply@github.com>2022-06-23 12:41:05 -0700
commit4aa6344f772d31c1f7b0676cbaf315104c4b30a2 (patch)
tree5fe9ded4256691d1e84ca0d9e3f03693dc4105bf /source/slang/slang-ir-dce.cpp
parent5bd366fa1d10b93d0460f7779fa24d1572c971ba (diff)
Preserve specialization cache in IR for specialization pass. (#2293)
* Perserve specialization cache in IR for specialization pass. * Fix compile error. * Fix. * Fix. * Fix test case. * Fix. Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source/slang/slang-ir-dce.cpp')
-rw-r--r--source/slang/slang-ir-dce.cpp46
1 files changed, 46 insertions, 0 deletions
diff --git a/source/slang/slang-ir-dce.cpp b/source/slang/slang-ir-dce.cpp
index 9ed5249fe..2d417221b 100644
--- a/source/slang/slang-ir-dce.cpp
+++ b/source/slang/slang-ir-dce.cpp
@@ -19,6 +19,10 @@ struct DeadCodeEliminationContext
IRModule* module;
IRDeadCodeEliminationOptions options;
+ // If we removed an inst, there may be still "weak references" to the inst.
+ // These uses will be replaced with `undefInst`.
+ IRInst* undefInst = nullptr;
+
// Our overall process is going to be to determine
// which instructions in the module are "live"
// and then eliminate anything that wasn't found to
@@ -77,6 +81,29 @@ struct DeadCodeEliminationContext
workList.add(inst);
}
+ IRInst* getUndefInst()
+ {
+ if (!undefInst)
+ {
+ for (auto inst : module->getModuleInst()->getChildren())
+ {
+ if (inst->getOp() == kIROp_undefined && inst->getDataType() && inst->getDataType()->getOp() == kIROp_VoidType)
+ {
+ undefInst = inst;
+ break;
+ }
+ }
+ if (!undefInst)
+ {
+ SharedIRBuilder builderStorage(module);
+ IRBuilder builder(&builderStorage);
+ builder.setInsertInto(module->getModuleInst());
+ undefInst = builder.emitUndefined(builder.getVoidType());
+ }
+ }
+ return undefInst;
+ }
+
// Given the basic infrastructrure above, let's
// dive into the task of actually finding all
// the live code in a module.
@@ -90,6 +117,13 @@ struct DeadCodeEliminationContext
//
markInstAsLive(module->getModuleInst());
+ // Ensure there is a global undef inst that is always alive.
+ // This undef inst will be used to fill in weak-referencing uses
+ // whose used value is marked as dead and eliminated.
+ // We always make sure this undef inst is available to prevent
+ // infiniate oscilating loops.
+ markInstAsLive(getUndefInst());
+
// Marking the module as live should have
// seeded our work list, so we can now start
// processing entries off of our work list
@@ -120,12 +154,20 @@ struct DeadCodeEliminationContext
UInt operandCount = inst->getOperandCount();
for( UInt ii = 0; ii < operandCount; ++ii )
{
+ // There are some type of operands that needs to be treated as
+ // "weak" references -- they can never hold things alive, and
+ // whenever we delete the referenced value, these operands needs
+ // to be replaced with `undef`.
switch (inst->getOp())
{
case kIROp_BoundInterfaceType:
if (inst->getOperand(ii)->getOp() == kIROp_WitnessTable)
continue;
break;
+ case kIROp_SpecializationDictionaryItem:
+ // Ignore all operands of SpecializationDictionaryItem.
+ // This inst is used as a cache and shouldn't hold anything alive.
+ continue;
default:
break;
}
@@ -192,6 +234,10 @@ struct DeadCodeEliminationContext
// because they must have been dead too (since we always
// mark the parent of a live instruction as live).
//
+ if (inst->hasUses())
+ {
+ inst->replaceUsesWith(getUndefInst());
+ }
inst->removeAndDeallocate();
changed = true;
}