diff options
| author | Yong He <yonghe@outlook.com> | 2024-05-06 14:53:27 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-06 14:53:27 -0700 |
| commit | 618428a87b8295347288262ea13eff63cc62aa56 (patch) | |
| tree | a602766742a437c3f0577ae6e3c1077c1b4e082c /source/slang/slang-ir-wrap-global-context.cpp | |
| parent | 2220d26c24b259075182672be22e1494b4affc95 (diff) | |
Delete `wrap-global-context` pass. (#4114)
* Delete `wrap-global-context` pass.
The pass was added for the metal backend without realizing that the existing `explicit-global-context` does 99% of the job. Instead of duplicating the logic in a different pass for metal, we extend same explicit-global-context pass to work for metal.
* Fix build.
Diffstat (limited to 'source/slang/slang-ir-wrap-global-context.cpp')
| -rw-r--r-- | source/slang/slang-ir-wrap-global-context.cpp | 286 |
1 files changed, 0 insertions, 286 deletions
diff --git a/source/slang/slang-ir-wrap-global-context.cpp b/source/slang/slang-ir-wrap-global-context.cpp deleted file mode 100644 index 32bf7995c..000000000 --- a/source/slang/slang-ir-wrap-global-context.cpp +++ /dev/null @@ -1,286 +0,0 @@ -#include "slang-ir-wrap-global-context.h" - -#include "slang-ir-util.h" - -namespace Slang -{ - struct WrapGlobalScopeContext - { - List<IRFunc*> entryPoints; - IRStructType* contextType; - struct GlobalVarInfo - { - IRStructKey* key; - }; - Dictionary<IRInst*, GlobalVarInfo> mapGlobalVarToInfo; - struct FuncInfo - { - IRInst* contextArg; - }; - Dictionary<IRFunc*, FuncInfo> mapFuncToInfo; - IRStringLit* findNameHint(IRInst* inst) - { - if (auto nameDecor = inst->findDecoration<IRNameHintDecoration>()) - return nameDecor->getNameOperand(); - if (auto linkageDecor = inst->findDecoration<IRLinkageDecoration>()) - return linkageDecor->getMangledNameOperand(); - return nullptr; - } - - // Move all global parameters to the entry point parameters, - // and replace them with global variables that are initialized with - // the entry point parameters. - void moveGlobalParametersToEntryPoint(IRModule* module) - { - Dictionary<IRInst*, IRInst*> mapGlobalParamToGlobalVar; - - IRBuilder builder(module); - - for (auto globalInst : module->getGlobalInsts()) - { - if (auto globalParam = as<IRGlobalParam>(globalInst)) - { - builder.setInsertBefore(globalParam); - auto globalVar = builder.createGlobalVar( - globalParam->getFullType(), - (int)AddressSpace::ThreadLocal); - if (auto name = findNameHint(globalParam)) - builder.addNameHintDecoration(globalVar, name); - mapGlobalParamToGlobalVar[globalParam] = globalVar; - } - } - - // For every entry point, we need to add a new parameter for each global parameter. - for (auto entryPoint : entryPoints) - { - auto firstBlock = entryPoint->getFirstBlock(); - auto paramInsertPoint = firstBlock->getFirstInst(); - struct ParamInfo - { - IRInst* newParam; - IRInst* globalVar; - }; - List<ParamInfo> newParams; - for (auto globalParam : mapGlobalParamToGlobalVar) - { - auto newParam = builder.createParam(globalParam.first->getFullType()); - newParam->insertBefore(paramInsertPoint); - globalParam.first->transferDecorationsTo(newParam); - newParams.add({newParam, globalParam.second}); - } - - // Insert assignments to the global variables at the start of the entry point. - builder.setInsertBefore(firstBlock->getFirstOrdinaryInst()); - for (auto& paramInfo : newParams) - { - auto globalVar = paramInfo.globalVar; - auto newParam = paramInfo.newParam; - builder.emitStore(globalVar, newParam); - } - } - - // Replace all uses of global parameters with a load from the global variable. - for (auto globalParam : mapGlobalParamToGlobalVar) - { - auto globalVar = globalParam.second; - traverseUses(globalParam.first, [&](IRUse* use) - { - auto user = use->getUser(); - builder.setInsertBefore(user); - auto load = builder.emitLoad(globalParam.first->getFullType(), globalVar); - builder.replaceOperand(use, load); - }); - globalParam.first->removeAndDeallocate(); - } - } - - void processModule(IRModule* module) - { - IRBuilder builder(module); - List<IRInst*> instsToRemove; - - List<IRFunc*> functions; - - // Collect all entry points and functions. - for (auto globalInst : module->getGlobalInsts()) - { - if (globalInst->findDecoration<IREntryPointDecoration>()) - entryPoints.add(as<IRFunc>(globalInst)); - if (auto func = as<IRFunc>(globalInst)) - functions.add(func); - } - - // Before everything, we need to move all global parameters to the entry point parameters. - // For each global parameter, e.g. `uniform float4 g;`, we will replace it with a global - // variable, e.g. `float4 _g;`, and add a new parameter to the each entry point, and copy - // the value from the entry point parameter to the global variable. - moveGlobalParametersToEntryPoint(module); - - // The next step is to wrap all global variables in a context type, and pass them around - // with explicit function parameters. - - // Collect all global variables. - for (auto globalInst : module->getGlobalInsts()) - { - if (auto globalVar = as<IRGlobalVar>(globalInst)) - { - auto key = builder.createStructKey(); - - if (auto name = findNameHint(globalVar)) - builder.addNameHintDecoration(key, name); - - GlobalVarInfo info; - info.key = key; - mapGlobalVarToInfo[globalVar] = info; - } - } - if (mapGlobalVarToInfo.getCount() == 0) - return; - - // Create the context type for the global scope. - contextType = builder.createStructType(); - builder.addNameHintDecoration(contextType, toSlice("_SlangGlobalContext")); - for (auto& fieldKV : mapGlobalVarToInfo) - { - auto ptrType = as<IRPtrTypeBase>(fieldKV.first->getFullType()); - if (!ptrType) - continue; - builder.createStructField( - contextType, fieldKV.second.key, ptrType->getValueType()); - } - - // Identify all functions that requires the global scope context. - - // First, add all functions to the work list if it directly uses a global variable. - List<IRFunc*> funcWorkList; - HashSet<IRFunc*> funcWorkListSet; - for (auto& fieldKV : mapGlobalVarToInfo) - { - auto globalVar = fieldKV.first; - for (auto use = globalVar->firstUse; use; use = use->nextUse) - { - if (auto userFunc = getParentFunc(use->getUser())) - { - if (funcWorkListSet.add(userFunc)) - funcWorkList.add(userFunc); - } - } - } - - // Next, propagate the call graph and add all functions that transitively uses a global variable. - for (Index i = 0; i < funcWorkList.getCount(); i++) - { - auto func = funcWorkList[i]; - for (auto use = func->firstUse; use; use = use->nextUse) - { - if (auto call = as<IRCall>(use->getUser())) - { - if (call->getCallee() != func) - continue; - if (auto callerFunc = as<IRFunc>(getParentFunc(call))) - { - if (funcWorkListSet.add(callerFunc)) - funcWorkList.add(callerFunc); - } - } - } - } - - // Now, everything in funcWorkListSet is a function that requires the global scope context. - // We go ahead and add the context type as the first parameter to these functions. - List<IRInst*> newCallArgs; - - auto threadPtrType = builder.getPtrType(kIROp_PtrType, contextType, (int)AddressSpace::ThreadLocal); - for (auto func : funcWorkListSet) - { - auto firstBlock = func->getFirstBlock(); - if (!firstBlock) - continue; - bool isEntryPoint = func->findDecoration<IREntryPointDecoration>() != nullptr; - FuncInfo funcInfo = {}; - if (isEntryPoint) - { - // If the function is an entry point, we need to declare a local variable to hold the context. - setInsertBeforeOrdinaryInst(&builder, firstBlock->getFirstOrdinaryInst()); - funcInfo.contextArg = builder.emitVar(contextType, (int)AddressSpace::ThreadLocal); - } - else - { - // For other functions, we just add the context as the first parameter. - builder.setInsertBefore(firstBlock->getFirstInst()); - funcInfo.contextArg = builder.emitParamAtHead(threadPtrType); - } - builder.addNameHintDecoration(funcInfo.contextArg, toSlice("_globalCtx")); - - mapFuncToInfo[func] = funcInfo; - - // Now go through the body of the function and insert the context as the first argument to all calls. - for (auto block : func->getBlocks()) - { - for (auto inst : block->getChildren()) - { - if (auto call = as<IRCall>(inst)) - { - if (funcWorkListSet.contains((IRFunc*)getResolvedInstForDecorations(call->getCallee()))) - { - builder.setInsertBefore(call); - newCallArgs.clear(); - newCallArgs.add(funcInfo.contextArg); - for (auto arg : call->getArgsList()) - newCallArgs.add(arg); - auto newCall = builder.emitCallInst(call->getFullType(), call->getCallee(), newCallArgs); - call->replaceUsesWith(newCall); - instsToRemove.add(call); - } - } - } - } - } - - // Next, we need to replace all accesses to global variables with accesses to the context. - for (auto globalVarKV : mapGlobalVarToInfo) - { - auto globalVar = globalVarKV.first; - auto key = globalVarKV.second.key; - traverseUses(globalVar, [&](IRUse* use) - { - auto user = use->getUser(); - auto parentFunc = getParentFunc(user); - if (!parentFunc) - return; - auto funcInfo = mapFuncToInfo.tryGetValue(parentFunc); - SLANG_ASSERT(funcInfo); - - auto contextArg = funcInfo->contextArg; - builder.setInsertBefore(user); - auto replacement = builder.emitFieldAddress( - builder.getPtrType( - kIROp_PtrType, - tryGetPointedToType(&builder, globalVar->getFullType()), - (int)AddressSpace::ThreadLocal), - contextArg, - key); - builder.replaceOperand(use, replacement); - }); - SLANG_ASSERT(!globalVar->hasUses()); - instsToRemove.add(globalVar); - } - - // Fix up all function types. - for (auto func : functions) - { - fixUpFuncType(func); - } - - // Finally, cleanup the IR by removing all the insts scheduled for removal. - for (auto inst : instsToRemove) - inst->removeAndDeallocate(); - } - }; - - void wrapGlobalScopeInContextType(IRModule* module) - { - WrapGlobalScopeContext context; - context.processModule(module); - } -} |
