Skip to content

Commit

Permalink
Remove globals if they're left unused after inlining
Browse files Browse the repository at this point in the history
This closes shader-slang#5607.
  • Loading branch information
aleino-nv committed Dec 11, 2024
1 parent 0eb539c commit a0366c8
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
42 changes: 41 additions & 1 deletion source/slang/slang-ir-legalize-global-values.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,39 @@
namespace Slang
{

void GlobalInstInliningContextGeneric::inlineGlobalValues(IRModule * module)
// Returns true iff 'rootInst', or any of it's descendants, satisfies 'predicate'.
template<typename P>
bool hasDescendantSatisfyingPredicate(IRInst* rootInst, P predicate)
{
IRInst* inst = rootInst;
while (true)
{
if (predicate(inst))
return true;

// Step to next IRInst according to preorder
if (inst->getFirstDecorationOrChild())
inst = inst->getFirstDecorationOrChild();
else
{
while (true)
{
if (inst == rootInst)
return false;
if (inst->getNextInst())
break;
inst = inst->getParent();
}
inst = inst->getNextInst();
}
}
return false;
}

void GlobalInstInliningContextGeneric::inlineGlobalValuesAndRemoveIfUnused(IRModule* module)
{
List<IRUse*> globalInstUsesToInline;
List<IRInst*> globalInstsToConsiderDeleting;

for (auto globalInst : module->getGlobalInsts())
{
Expand All @@ -19,6 +49,7 @@ void GlobalInstInliningContextGeneric::inlineGlobalValues(IRModule * module)
if (getParentFunc(use->getUser()) != nullptr)
globalInstUsesToInline.add(use);
}
globalInstsToConsiderDeleting.add(globalInst);
}
}

Expand All @@ -32,6 +63,15 @@ void GlobalInstInliningContextGeneric::inlineGlobalValues(IRModule * module)
if (val != use->get())
builder.replaceOperand(use, val);
}

// Since certain globals that appear in the IR are considered illegal for all targets,
// e.g. calls to functions, we delete globals which no longer have uses (or children with uses) after inlining.
for (auto& globalInst: globalInstsToConsiderDeleting)
{
if (!hasDescendantSatisfyingPredicate(globalInst, [](IRInst* inst){return inst->hasUses();}))
globalInst->removeAndDeallocate();
}

}

bool GlobalInstInliningContextGeneric::isLegalGlobalInst(IRInst* inst)
Expand Down
3 changes: 2 additions & 1 deletion source/slang/slang-ir-legalize-global-values.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ struct GlobalInstInliningContextGeneric
virtual IRInst* getOutsideASM(IRInst* beforeInst) =0;

// Inline global values that can't represented by the target to their use sites.
void inlineGlobalValues(IRModule * module);
// If this leaves any global unused, then remove it.
void inlineGlobalValuesAndRemoveIfUnused(IRModule * module);

// Opcodes that can exist in global scope, as long as the operands are.
bool isLegalGlobalInst(IRInst* inst);
Expand Down
2 changes: 1 addition & 1 deletion source/slang/slang-ir-spirv-legalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2016,7 +2016,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
}

GlobalInstInliningContext().inlineGlobalValues(m_module);
GlobalInstInliningContext().inlineGlobalValuesAndRemoveIfUnused(m_module);

// Some legalization processing may change the function parameter types,
// so we need to update the function types to match that.
Expand Down
4 changes: 3 additions & 1 deletion source/slang/slang-ir-wgsl-legalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,9 @@ void legalizeIRForWGSL(IRModule* module, DiagnosticSink* sink)
// Go through every instruction in the module and legalize them as needed.
context.processInst(module->getModuleInst());

GlobalInstInliningContext().inlineGlobalValues(module);
// Some global insts are illegal, e.g. function calls.
// We need to inline and remove those.
GlobalInstInliningContext().inlineGlobalValuesAndRemoveIfUnused(module);
}

} // namespace Slang

0 comments on commit a0366c8

Please sign in to comment.