diff options
Diffstat (limited to 'source/slang/slang-ir-specialize-buffer-load-arg.cpp')
| -rw-r--r-- | source/slang/slang-ir-specialize-buffer-load-arg.cpp | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/source/slang/slang-ir-specialize-buffer-load-arg.cpp b/source/slang/slang-ir-specialize-buffer-load-arg.cpp new file mode 100644 index 000000000..353c6a104 --- /dev/null +++ b/source/slang/slang-ir-specialize-buffer-load-arg.cpp @@ -0,0 +1,96 @@ +// slang-ir-specialize-buffer-load-arg.cpp +#include "slang-ir-specialize-buffer-load-arg.h" + +#include "slang-ir.h" +#include "slang-ir-insts.h" +#include "slang-ir-specialize-function-call.h" + +namespace Slang +{ + +// This file implements a pass that translates function call sites where +// the result of a buffer load from a global shader parameter (e.g., a +// global constant buffer) is being passed through to the callee. It +// replaces those with calls to specialized callee functions that directly +// reference the chosen global. +// +// As swith most of our IR passes, we encapsulate the logic here in a context +// type so that the data that needs to be shared throughout the pass can +// be conveniently scoped. + +struct FuncBufferLoadSpecializationCondition : FunctionCallSpecializeCondition +{ + typedef FunctionCallSpecializeCondition Super; + + virtual bool doesParamWantSpecialization(IRParam* param, IRInst* arg) + { + // We only want to specialize for `struct` types and not base types. + // + // TODO: We might want to consider some criteria here for the "large-ness" + // of a structure (in terms of bytes and/or fields), so that we don't + // eliminate loads of sufficiently small types (which are cheap to pass + // by value). + // + auto paramType = param->getDataType(); + if(!as<IRStructType>(paramType)) + return false; + + // We also only want to specialize for arguments that are a load + // from some kind of global shader parameter. + // + IRInst* a = arg; + if (auto argLoad = as<IRLoad>(arg)) + { + a = argLoad->getPtr(); + } + else + { + return false; + } + + // We want to handle loads from a shader parameter that is an array + // of buffers, and not just a single global buffer. + // + while (auto argGetElement = as<IRGetElement>(a)) + { + a = argGetElement->getBase(); + } + + // The "root" of the parameter must be a reference to a global-scope + // shader parameter, so that we know we can substitute it into the callee. + // + if (auto argGlobalParam = as<IRGlobalParam>(a)) + { + return true; + } + else + { + return false; + } + + // TODO: There are other patterns that we could attempt to optimize here. + // For example, this logic only handles loads of the *entire* contents of + // a buffer, so it would miss: + // + // * A load of a large structure from field in a constant buffer, so that + // the value loaded is not the entire buffer contents. + // + // * A load of a large structure from a structured buffer, or any other kind + // of buffer that requires an index. + // + // * Any resource load that is not expressed at the IR level with a `load` + // instruction (e.g., those that might use an intrinsic function). + // + } +}; + +void specializeFuncsForBufferLoadArgs( + BackEndCompileRequest* compileRequest, + TargetRequest* targetRequest, + IRModule* module) +{ + FuncBufferLoadSpecializationCondition condition; + specializeFunctionCalls(compileRequest, targetRequest, module, &condition); +} + +} |
