summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-specialize-target-switch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-ir-specialize-target-switch.cpp')
-rw-r--r--source/slang/slang-ir-specialize-target-switch.cpp30
1 files changed, 22 insertions, 8 deletions
diff --git a/source/slang/slang-ir-specialize-target-switch.cpp b/source/slang/slang-ir-specialize-target-switch.cpp
index f4cb6bfa7..fac1dd484 100644
--- a/source/slang/slang-ir-specialize-target-switch.cpp
+++ b/source/slang/slang-ir-specialize-target-switch.cpp
@@ -7,13 +7,15 @@
namespace Slang
{
- void specializeTargetSwitch(TargetRequest* target, IRGlobalValueWithCode* code)
+ void specializeTargetSwitch(TargetRequest* target, IRGlobalValueWithCode* code, DiagnosticSink* sink)
{
bool changed = false;
for (auto block : code->getBlocks())
{
+ bool failedImplies = false;
if (auto targetSwitch = as<IRTargetSwitch>(block->getTerminator()))
{
+ bool isEqual;
CapabilitySet bestCapSet = CapabilitySet::makeInvalid();
IRBlock* targetBlock = nullptr;
for (UInt i = 0; i < targetSwitch->getCaseCount(); i++)
@@ -22,14 +24,22 @@ namespace Slang
if (target->getTargetCaps().isIncompatibleWith(cap))
continue;
CapabilitySet capSet;
- if (cap == CapabilityName::Invalid)
+ if (cap == CapabilityName::Invalid) // `default` case
capSet = CapabilitySet::makeEmpty();
else
capSet = CapabilitySet(cap);
- if (capSet.isBetterForTarget(bestCapSet, target->getTargetCaps()))
+ bool isBetterForTarget = capSet.isBetterForTarget(bestCapSet, target->getTargetCaps(), isEqual);
+ if (isBetterForTarget)
{
- targetBlock = targetSwitch->getCaseBlock(i);
- bestCapSet = capSet;
+ bool targetImpliesCapSet = (target->getTargetCaps().implies(capSet, true) || capSet.isEmpty());
+ if (targetImpliesCapSet)
+ {
+ // Now check if bestCapSet contains targetCaps. If it does not then this is an invalid target
+ targetBlock = targetSwitch->getCaseBlock(i);
+ bestCapSet = capSet;
+ }
+ else
+ failedImplies = true;
}
}
IRBuilder builder(targetSwitch);
@@ -40,6 +50,10 @@ namespace Slang
}
else
{
+ // only error if we have the chance of setting a valid target switch, but did not due to incompatability within same `target` atom.
+ // Otherwise we will have an issue when we process a `__target_switch() { case metal: return; }` for glsl targets.
+ if(failedImplies)
+ sink->diagnose(targetSwitch->sourceLoc, Diagnostics::profileIncompatibleWithTargetSwitch, target->getTargetCaps());
builder.emitMissingReturn();
}
targetSwitch->removeAndDeallocate();
@@ -53,19 +67,19 @@ namespace Slang
}
}
- void specializeTargetSwitch(TargetRequest* target, IRModule* module)
+ void specializeTargetSwitch(TargetRequest* target, IRModule* module, DiagnosticSink* sink)
{
for (auto globalInst : module->getGlobalInsts())
{
if (auto code = as<IRGlobalValueWithCode>(globalInst))
{
- specializeTargetSwitch(target, code);
+ specializeTargetSwitch(target, code, sink);
if (auto gen = as<IRGeneric>(code))
{
auto retVal = findGenericReturnVal(gen);
if (auto innerCode = as<IRGlobalValueWithCode>(retVal))
{
- specializeTargetSwitch(target, innerCode);
+ specializeTargetSwitch(target, innerCode, sink);
}
}
}