diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /source/slang/slang-ir-uniformity.cpp | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'source/slang/slang-ir-uniformity.cpp')
| -rw-r--r-- | source/slang/slang-ir-uniformity.cpp | 553 |
1 files changed, 281 insertions, 272 deletions
diff --git a/source/slang/slang-ir-uniformity.cpp b/source/slang/slang-ir-uniformity.cpp index 44ac6cb34..666f72d0c 100644 --- a/source/slang/slang-ir-uniformity.cpp +++ b/source/slang/slang-ir-uniformity.cpp @@ -1,216 +1,217 @@ #include "slang-ir-uniformity.h" -#include "slang-ir.h" +#include "slang-ir-dominators.h" #include "slang-ir-insts.h" #include "slang-ir-util.h" -#include "slang-ir-dominators.h" +#include "slang-ir.h" namespace Slang { - struct ValidateUniformityContext - { - IRModule* module; - DiagnosticSink* sink; +struct ValidateUniformityContext +{ + IRModule* module; + DiagnosticSink* sink; - HashSet<IRInst*> nonUniformInsts; - ValidateUniformityContext* parentContext = nullptr; - IRCall* call = nullptr; - IRFunc* currentCallee = nullptr; + HashSet<IRInst*> nonUniformInsts; + ValidateUniformityContext* parentContext = nullptr; + IRCall* call = nullptr; + IRFunc* currentCallee = nullptr; - bool isInstNonUniform(IRInst* inst) + bool isInstNonUniform(IRInst* inst) + { + auto context = this; + while (context) { - auto context = this; - while (context) - { - if (context->nonUniformInsts.contains(inst)) - return true; - context = context->parentContext; - } - return false; + if (context->nonUniformInsts.contains(inst)) + return true; + context = context->parentContext; } + return false; + } + + struct FunctionNonUniformInfoKey + { + IRFunc* func; + UIntSet nonUniformParams; - struct FunctionNonUniformInfoKey + bool operator==(const FunctionNonUniformInfoKey& other) const + { + return func == other.func && nonUniformParams == other.nonUniformParams; + } + HashCode getHashCode() const { - IRFunc* func; - UIntSet nonUniformParams; + return combineHash(Slang::getHashCode(func), nonUniformParams.getHashCode()); + } + }; - bool operator==(const FunctionNonUniformInfoKey& other) const + struct FunctionNonUniformInfo + { + UIntSet nonUniformParams; + bool isResultNonUniform = false; + }; + + Dictionary<FunctionNonUniformInfoKey, FunctionNonUniformInfo> functionNonUniformInfos; + + template<typename F> + void traverseControlDependentBlocks(IRDominatorTree* dom, IRInst* inst, const F& f) + { + auto block = as<IRBlock>(inst->getParent()); + if (!block) + return; + for (auto idom = dom->getImmediateDominator(block); idom; + idom = dom->getImmediateDominator(idom)) + { + if (as<IRUnconditionalBranch>(idom->getTerminator())) + continue; + if (auto ifelse = as<IRIfElse>(idom->getTerminator())) { - return func == other.func && nonUniformParams == other.nonUniformParams; + if (dom->dominates(ifelse->getAfterBlock(), block)) + continue; } - HashCode getHashCode() const + else if (auto switchInst = as<IRSwitch>(idom->getTerminator())) { - return combineHash(Slang::getHashCode(func), nonUniformParams.getHashCode()); + if (dom->dominates(switchInst->getBreakLabel(), block)) + continue; } - }; - - struct FunctionNonUniformInfo - { - UIntSet nonUniformParams; - bool isResultNonUniform = false; - }; - - Dictionary<FunctionNonUniformInfoKey, FunctionNonUniformInfo> functionNonUniformInfos; - - template<typename F> - void traverseControlDependentBlocks(IRDominatorTree* dom, IRInst* inst, const F& f) - { - auto block = as<IRBlock>(inst->getParent()); - if (!block) - return; - for (auto idom = dom->getImmediateDominator(block); idom; idom = dom->getImmediateDominator(idom)) + else if (auto loopInst = as<IRLoop>(idom->getTerminator())) { - if (as<IRUnconditionalBranch>(idom->getTerminator())) + if (dom->dominates(loopInst->getBreakBlock(), block)) continue; - if (auto ifelse = as<IRIfElse>(idom->getTerminator())) - { - if (dom->dominates(ifelse->getAfterBlock(), block)) - continue; - } - else if (auto switchInst = as<IRSwitch>(idom->getTerminator())) - { - if (dom->dominates(switchInst->getBreakLabel(), block)) - continue; - } - else if (auto loopInst = as<IRLoop>(idom->getTerminator())) - { - if (dom->dominates(loopInst->getBreakBlock(), block)) - continue; - } - f(idom); } + f(idom); } + } - FunctionNonUniformInfo* getFunctionNonUniformInfo(IRCall* callInst, const FunctionNonUniformInfoKey& key) - { - if (auto rs = functionNonUniformInfos.tryGetValue(key)) - return rs; + FunctionNonUniformInfo* getFunctionNonUniformInfo( + IRCall* callInst, + const FunctionNonUniformInfoKey& key) + { + if (auto rs = functionNonUniformInfos.tryGetValue(key)) + return rs; - // Is the function already being analyzed? If so exit early to avoid infinite recursion. - for (auto context = this; context; context = context->parentContext) - { - if (context->currentCallee == key.func) - return nullptr; - } + // Is the function already being analyzed? If so exit early to avoid infinite recursion. + for (auto context = this; context; context = context->parentContext) + { + if (context->currentCallee == key.func) + return nullptr; + } - // If the function body has target intrinsic, we can't analyze it, and we - // will use the fallback behavior (result is non-uniform if any of its arguments are non-uniform). - for (auto block : key.func->getBlocks()) + // If the function body has target intrinsic, we can't analyze it, and we + // will use the fallback behavior (result is non-uniform if any of its arguments are + // non-uniform). + for (auto block : key.func->getBlocks()) + { + if (as<IRGenericAsm>(block->getTerminator())) { - if (as<IRGenericAsm>(block->getTerminator())) - { - return nullptr; - } + return nullptr; } + } - ValidateUniformityContext subContext; - subContext.module = module; - subContext.sink = sink; - subContext.parentContext = this; + ValidateUniformityContext subContext; + subContext.module = module; + subContext.sink = sink; + subContext.parentContext = this; - List<IRInst*> workList; - Index paramIndex = 0; - for (auto param : key.func->getParams()) + List<IRInst*> workList; + Index paramIndex = 0; + for (auto param : key.func->getParams()) + { + if (key.nonUniformParams.contains(UInt(paramIndex))) { - if (key.nonUniformParams.contains(UInt(paramIndex))) - { - subContext.nonUniformInsts.add(param); - workList.add(param); - } - paramIndex++; + subContext.nonUniformInsts.add(param); + workList.add(param); } - subContext.call = callInst; - subContext.currentCallee = key.func; - subContext.propagateNonUniform(key.func, workList); + paramIndex++; + } + subContext.call = callInst; + subContext.currentCallee = key.func; + subContext.propagateNonUniform(key.func, workList); - FunctionNonUniformInfo info; - info.nonUniformParams = key.nonUniformParams; - paramIndex = 0; - for (auto param : key.func->getParams()) + FunctionNonUniformInfo info; + info.nonUniformParams = key.nonUniformParams; + paramIndex = 0; + for (auto param : key.func->getParams()) + { + if (subContext.nonUniformInsts.contains(param)) { - if (subContext.nonUniformInsts.contains(param)) - { - info.nonUniformParams.add(paramIndex); - } - paramIndex++; + info.nonUniformParams.add(paramIndex); } + paramIndex++; + } - // If the function has [NonUniformReturn] attribute, - // treat its return value as non uniform. - if (key.func->findDecorationImpl(kIROp_NonDynamicUniformReturnDecoration)) - { - info.isResultNonUniform = true; - } - else + // If the function has [NonUniformReturn] attribute, + // treat its return value as non uniform. + if (key.func->findDecorationImpl(kIROp_NonDynamicUniformReturnDecoration)) + { + info.isResultNonUniform = true; + } + else + { + // The return value is non-uniform if the any values used in IRReturn is + // non-uniform, or if the return insts are control-dependent on non-uniform + // values. + for (auto bb : key.func->getBlocks()) { - // The return value is non-uniform if the any values used in IRReturn is - // non-uniform, or if the return insts are control-dependent on non-uniform - // values. - for (auto bb : key.func->getBlocks()) + if (auto ret = as<IRReturn>(bb->getTerminator())) { - if (auto ret = as<IRReturn>(bb->getTerminator())) + if (subContext.isInstNonUniform(ret->getVal()) || + subContext.isInstNonUniform(ret)) { - if (subContext.isInstNonUniform(ret->getVal()) || subContext.isInstNonUniform(ret)) - { - info.isResultNonUniform = true; - break; - } + info.isResultNonUniform = true; + break; } } } - functionNonUniformInfos[key] = info; - return functionNonUniformInfos.tryGetValue(key); } + functionNonUniformInfos[key] = info; + return functionNonUniformInfos.tryGetValue(key); + } - bool isDynamicUniformLocation(IRInst* addr) + bool isDynamicUniformLocation(IRInst* addr) + { + while (addr) { - while (addr) + switch (addr->getOp()) { - switch (addr->getOp()) - { - case kIROp_FieldAddress: - if (as<IRFieldAddress>(addr)->getField()->findDecoration<IRDynamicUniformDecoration>()) - return true; - addr = as<IRFieldAddress>(addr)->getBase(); - break; - case kIROp_GetElementPtr: - addr = as<IRGetElementPtr>(addr)->getBase(); - break; - case kIROp_GetOffsetPtr: - addr = addr->getOperand(0); - break; - case kIROp_Param: - case kIROp_Var: - return addr->findDecoration<IRDynamicUniformDecoration>() != nullptr; - default: - addr = nullptr; - } + case kIROp_FieldAddress: + if (as<IRFieldAddress>(addr) + ->getField() + ->findDecoration<IRDynamicUniformDecoration>()) + return true; + addr = as<IRFieldAddress>(addr)->getBase(); + break; + case kIROp_GetElementPtr: addr = as<IRGetElementPtr>(addr)->getBase(); break; + case kIROp_GetOffsetPtr: addr = addr->getOperand(0); break; + case kIROp_Param: + case kIROp_Var: return addr->findDecoration<IRDynamicUniformDecoration>() != nullptr; + default: addr = nullptr; } - return false; } + return false; + } - void propagateNonUniform(IRFunc* root, List<IRInst*>& workList) - { - InstWorkList nextWorkList(module); - InstHashSet workListSet(module); + void propagateNonUniform(IRFunc* root, List<IRInst*>& workList) + { + InstWorkList nextWorkList(module); + InstHashSet workListSet(module); - auto addToWorkList = [&](IRInst* inst) - { - if (workListSet.add(inst)) - { - nonUniformInsts.add(inst); - nextWorkList.add(inst); - } - }; + auto addToWorkList = [&](IRInst* inst) + { + if (workListSet.add(inst)) + { + nonUniformInsts.add(inst); + nextWorkList.add(inst); + } + }; - // Go through the children first to identify initial non-uniform insts. - for (auto block : root->getBlocks()) + // Go through the children first to identify initial non-uniform insts. + for (auto block : root->getBlocks()) + { + for (auto inst = block->getFirstInst(); inst; inst = inst->getNextInst()) { - for (auto inst = block->getFirstInst(); inst; inst = inst->getNextInst()) + switch (inst->getOp()) { - switch (inst->getOp()) - { - case kIROp_Call: + case kIROp_Call: { auto callInst = as<IRCall>(inst); auto callee = getResolvedInstForDecorations(callInst->getCallee()); @@ -220,74 +221,70 @@ namespace Slang } break; } - } } } + } - auto dom = module->findOrCreateDominatorTree(root); + auto dom = module->findOrCreateDominatorTree(root); - auto visitControlDependentBlock = [&](IRBlock* dependentBlock) + auto visitControlDependentBlock = [&](IRBlock* dependentBlock) + { + if (!dependentBlock) + return; + for (auto block : dom->getProperlyDominatedBlocks(dependentBlock)) + { + for (auto inst = block->getFirstInst(); inst; inst = inst->getNextInst()) { - if (!dependentBlock) - return; - for (auto block : dom->getProperlyDominatedBlocks(dependentBlock)) + switch (inst->getOp()) { - for (auto inst = block->getFirstInst(); inst; inst = inst->getNextInst()) + case kIROp_Store: + case kIROp_SwizzledStore: addToWorkList(inst->getOperand(0)); break; + case kIROp_Return: addToWorkList(inst); break; + case kIROp_Call: { - switch (inst->getOp()) + auto call = as<IRCall>(inst); + for (UInt i = 0; i < call->getArgCount(); i++) { - case kIROp_Store: - case kIROp_SwizzledStore: - addToWorkList(inst->getOperand(0)); - break; - case kIROp_Return: - addToWorkList(inst); - break; - case kIROp_Call: - { - auto call = as<IRCall>(inst); - for (UInt i = 0; i < call->getArgCount(); i++) - { - if (as<IRPtrTypeBase>(call->getArg(i))) - addToWorkList(call->getArg(i)); - } - } - break; + if (as<IRPtrTypeBase>(call->getArg(i))) + addToWorkList(call->getArg(i)); } } + break; } - }; + } + } + }; - while (workList.getCount()) + while (workList.getCount()) + { + for (Index i = 0; i < workList.getCount(); i++) { - for (Index i = 0; i < workList.getCount(); i++) + auto inst = workList[i]; + for (auto use = inst->firstUse; use; use = use->nextUse) { - auto inst = workList[i]; - for (auto use = inst->firstUse; use; use = use->nextUse) + auto user = use->getUser(); + if (as<IRAttr>(user)) + continue; + if (as<IRDecoration>(user)) + continue; + switch (user->getOp()) { - auto user = use->getUser(); - if (as<IRAttr>(user)) - continue; - if (as<IRDecoration>(user)) - continue; - switch (user->getOp()) - { - case kIROp_TreatAsDynamicUniform: - continue; - case kIROp_FieldAddress: + case kIROp_TreatAsDynamicUniform: continue; + case kIROp_FieldAddress: { if (isDynamicUniformLocation(user)) continue; break; } - case kIROp_FieldExtract: + case kIROp_FieldExtract: { - if (as<IRFieldExtract>(user)->findDecoration<IRDynamicUniformDecoration>()) + if (as<IRFieldExtract>(user) + ->findDecoration<IRDynamicUniformDecoration>()) continue; break; } - case kIROp_SwizzledStore: - case kIROp_Store: + case kIROp_SwizzledStore: + case kIROp_Store: { if (use == user->getOperands() + 1) { @@ -295,39 +292,45 @@ namespace Slang addToWorkList(ptr); if (isDynamicUniformLocation(ptr)) { - sink->diagnose(user->sourceLoc, Diagnostics::expectDynamicUniformValue, ptr); + sink->diagnose( + user->sourceLoc, + Diagnostics::expectDynamicUniformValue, + ptr); } else { - // Conservatively treat the entire composite at root addr as non-uniform. + // Conservatively treat the entire composite at root addr as + // non-uniform. auto addrRoot = getRootAddr(ptr); addToWorkList(addrRoot); } } break; } - case kIROp_ifElse: + case kIROp_ifElse: { auto ifElse = as<IRIfElse>(user); visitControlDependentBlock(ifElse->getTrueBlock()); visitControlDependentBlock(ifElse->getFalseBlock()); - // Mark phi nodes as non-uniform if any of its incoming values are non-uniform. + // Mark phi nodes as non-uniform if any of its incoming values are + // non-uniform. for (auto param : ifElse->getAfterBlock()->getParams()) addToWorkList(param); break; } - case kIROp_Switch: + case kIROp_Switch: { auto switchInst = as<IRSwitch>(user); for (UInt c = 0; c < switchInst->getCaseCount(); c++) visitControlDependentBlock(switchInst->getCaseLabel(c)); visitControlDependentBlock(switchInst->getDefaultLabel()); - // Mark phi nodes as non-uniform if any of its incoming values are non-uniform. + // Mark phi nodes as non-uniform if any of its incoming values are + // non-uniform. for (auto param : switchInst->getBreakLabel()->getParams()) addToWorkList(param); break; } - case kIROp_Call: + case kIROp_Call: { auto callInst = as<IRCall>(user); auto callee = getResolvedInstForDecorations(callInst->getCallee()); @@ -344,7 +347,10 @@ namespace Slang auto param = getParamAt(func->getFirstBlock(), argi); if (param->findDecoration<IRDynamicUniformDecoration>()) { - sink->diagnose(callInst->sourceLoc, Diagnostics::expectDynamicUniformArgument, param); + sink->diagnose( + callInst->sourceLoc, + Diagnostics::expectDynamicUniformArgument, + param); } else { @@ -371,7 +377,9 @@ namespace Slang } // The default behavior for calls is that the result is non-uniform if // any of its arguments are non-uniform. - bool isNonUniformCall = callee->findDecorationImpl(kIROp_NonDynamicUniformReturnDecoration) != nullptr; + bool isNonUniformCall = + callee->findDecorationImpl( + kIROp_NonDynamicUniformReturnDecoration) != nullptr; if (!isNonUniformCall) { for (UInt argi = 0; argi < callInst->getArgCount(); argi++) @@ -391,7 +399,8 @@ namespace Slang if (as<IRPtrTypeBase>(callInst->getArg(argi)->getDataType())) { addToWorkList(callInst->getArg(argi)); - // Conservatively treat the entire composite at root addr as non-uniform. + // Conservatively treat the entire composite at root addr as + // non-uniform. auto addrRoot = getRootAddr(callInst->getArg(argi)); addToWorkList(addrRoot); } @@ -399,84 +408,84 @@ namespace Slang } break; } - default: - break; - } - addToWorkList(user); + default: break; } + addToWorkList(user); } - workList.swapWith(nextWorkList.getList()); - nextWorkList.clear(); } + workList.swapWith(nextWorkList.getList()); + nextWorkList.clear(); } + } - void analyzeModule() - { - InstWorkList workList(module); + void analyzeModule() + { + InstWorkList workList(module); - for (auto globalInst : module->getGlobalInsts()) + for (auto globalInst : module->getGlobalInsts()) + { + if (auto code = as<IRGlobalValueWithCode>(globalInst)) { - if (auto code = as<IRGlobalValueWithCode>(globalInst)) + auto func = getResolvedInstForDecorations(code); + if (func->findDecorationImpl(kIROp_NonDynamicUniformReturnDecoration)) { - auto func = getResolvedInstForDecorations(code); - if (func->findDecorationImpl(kIROp_NonDynamicUniformReturnDecoration)) - { - nonUniformInsts.add(code); - } + nonUniformInsts.add(code); } - if (globalInst->findDecoration<IREntryPointDecoration>()) + } + if (globalInst->findDecoration<IREntryPointDecoration>()) + { + auto func = as<IRFunc>(globalInst); + if (!func) + continue; + for (auto param : func->getParams()) { - auto func = as<IRFunc>(globalInst); - if (!func) - continue; - for (auto param : func->getParams()) + auto varLayout = findVarLayout(param); + if (isVaryingParameter(varLayout) || + varLayout->findAttr<IRSystemValueSemanticAttr>()) { - auto varLayout = findVarLayout(param); - if (isVaryingParameter(varLayout) || varLayout->findAttr<IRSystemValueSemanticAttr>()) - { - nonUniformInsts.add(param); - workList.add(param); - } + nonUniformInsts.add(param); + workList.add(param); } - currentCallee = func; - call = nullptr; - propagateNonUniform(func, workList.getList()); } + currentCallee = func; + call = nullptr; + propagateNonUniform(func, workList.getList()); } - workList.clear(); - - eliminateAsDynamicUniformInst(); } + workList.clear(); + + eliminateAsDynamicUniformInst(); + } - void eliminateAsDynamicUniformInst() + void eliminateAsDynamicUniformInst() + { + InstWorkList workList(module); + workList.add(module->getModuleInst()); + for (Index i = 0; i < workList.getCount(); i++) { - InstWorkList workList(module); - workList.add(module->getModuleInst()); - for (Index i = 0; i < workList.getCount(); i++) + auto inst = workList[i]; + if (inst->getOp() == kIROp_TreatAsDynamicUniform) { - auto inst = workList[i]; - if (inst->getOp() == kIROp_TreatAsDynamicUniform) - { - auto val = inst->getOperand(0); - inst->replaceUsesWith(val); - inst->removeAndDeallocate(); - } - else + auto val = inst->getOperand(0); + inst->replaceUsesWith(val); + inst->removeAndDeallocate(); + } + else + { + for (auto child = inst->getFirstChild(); child; child = child->getNextInst()) { - for (auto child = inst->getFirstChild(); child; child = child->getNextInst()) - { - workList.add(child); - } + workList.add(child); } } } - }; - - void validateUniformity(IRModule* module, DiagnosticSink* sink) - { - ValidateUniformityContext context; - context.module = module; - context.sink = sink; - context.analyzeModule(); } +}; + +void validateUniformity(IRModule* module, DiagnosticSink* sink) +{ + ValidateUniformityContext context; + context.module = module; + context.sink = sink; + context.analyzeModule(); } +} // namespace Slang |
