diff options
Diffstat (limited to 'source/slang/slang-ir-specialize-target-switch.cpp')
| -rw-r--r-- | source/slang/slang-ir-specialize-target-switch.cpp | 30 |
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); } } } |
