summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-lower-generics.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2020-06-17 13:08:27 -0700
committerGitHub <noreply@github.com>2020-06-17 13:08:27 -0700
commitcd7f01b63a52eaaad00088524801e502bcb0f168 (patch)
treea04b6d9f2f7f85466b537a8aedeb3795339fae71 /source/slang/slang-ir-lower-generics.cpp
parentca503d48bff31d3990d4740751d5f6a4a48bfe5a (diff)
Generate dynamic C++ code for the minimal test case. (#1391)
* Add IR pass to lower generics into ordinary functions. * Fix project files * Emit dynamic C++ code for simple generics and witness tables. Fixes #1386. * Remove -dump-ir flag. * Fixups.
Diffstat (limited to 'source/slang/slang-ir-lower-generics.cpp')
-rw-r--r--source/slang/slang-ir-lower-generics.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp
new file mode 100644
index 000000000..4378d396f
--- /dev/null
+++ b/source/slang/slang-ir-lower-generics.cpp
@@ -0,0 +1,158 @@
+// slang-ir-lower-generics.cpp
+#include "slang-ir-lower-generics.h"
+
+#include "slang-ir.h"
+#include "slang-ir-clone.h"
+#include "slang-ir-insts.h"
+
+namespace Slang
+{
+ struct GenericsLoweringContext;
+
+ struct GenericsLoweringContext
+ {
+ // For convenience, we will keep a pointer to the module
+ // we are processing.
+ IRModule* module;
+
+ Dictionary<IRInst*, IRInst*> loweredGenericFunctions;
+
+ SharedIRBuilder sharedBuilderStorage;
+
+ // We will use a single work list of instructions that need
+ // to be considered for lowering.
+ //
+ List<IRInst*> workList;
+ HashSet<IRInst*> workListSet;
+
+ void addToWorkList(
+ IRInst* inst)
+ {
+ // We will ignore any code that is nested under a generic,
+ // because they will be recursively processed through specialized
+ // call sites.
+ //
+ for (auto ii = inst->getParent(); ii; ii = ii->getParent())
+ {
+ if (as<IRGeneric>(ii))
+ return;
+ }
+
+ if (workListSet.Contains(inst))
+ return;
+
+ workList.add(inst);
+ workListSet.Add(inst);
+ }
+
+ IRInst* lowerGenericFunction(IRInst* genericValue)
+ {
+ IRInst* result = nullptr;
+ if (loweredGenericFunctions.TryGetValue(genericValue, result))
+ return result;
+ auto genericParent = as<IRGeneric>(genericValue);
+ SLANG_ASSERT(genericParent);
+ auto func = as<IRFunc>(findGenericReturnVal(genericParent));
+ SLANG_ASSERT(func);
+ if (!func->isDefinition())
+ {
+ loweredGenericFunctions[genericValue] = genericValue;
+ return genericValue;
+ }
+ IRCloneEnv cloneEnv;
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedBuilderStorage;
+ builder.setInsertBefore(genericParent);
+ auto loweredFunc = cloneInstAndOperands(&cloneEnv, &builder, func);
+ List<IRInst*> clonedParams;
+ for (auto genericParam : genericParent->getParams())
+ {
+ auto clonedParam = cloneInst(&cloneEnv, &builder, genericParam);
+ cloneEnv.mapOldValToNew[genericParam] = clonedParam;
+ clonedParams.add(clonedParam);
+ }
+ cloneInstDecorationsAndChildren(&cloneEnv, &sharedBuilderStorage, func, loweredFunc);
+ auto block = as<IRBlock>(loweredFunc->getFirstChild());
+ for (auto param : clonedParams)
+ {
+ param->removeFromParent();
+ block->addParam(as<IRParam>(param));
+ }
+ loweredGenericFunctions[genericValue] = loweredFunc;
+ addToWorkList(loweredFunc);
+ return loweredFunc;
+ }
+
+ void processInst(IRInst* inst)
+ {
+ if (auto callInst = as<IRCall>(inst))
+ {
+ // If we see a call(specialize(gFunc, Targs), args),
+ // translate it into call(gFunc, args, Targs).
+ auto funcOperand = callInst->getOperand(0);
+ if (auto specializeInst = as<IRSpecialize>(funcOperand))
+ {
+ auto loweredFunc = lowerGenericFunction(specializeInst->getOperand(0));
+ if (loweredFunc == specializeInst->getOperand(0))
+ {
+ // This is an intrinsic function, don't transform.
+ return;
+ }
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+ builder->sharedBuilder = &sharedBuilderStorage;
+ builder->setInsertBefore(inst);
+ List<IRInst*> args;
+ for (UInt i = 0; i < callInst->getArgCount(); i++)
+ args.add(callInst->getArg(i));
+ for (UInt i = 0; i < specializeInst->getArgCount(); i++)
+ args.add(specializeInst->getArg(i));
+ auto newCall = builder->emitCallInst(callInst->getFullType(), loweredFunc, args);
+ callInst->replaceUsesWith(newCall);
+ callInst->removeAndDeallocate();
+ }
+ }
+ }
+
+ void processModule()
+ {
+ // We start by initializing our shared IR building state,
+ // since we will re-use that state for any code we
+ // generate along the way.
+ //
+ SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
+ sharedBuilder->module = module;
+ sharedBuilder->session = module->session;
+
+ addToWorkList(module->getModuleInst());
+
+ while (workList.getCount() != 0)
+ {
+ // We will then iterate until our work list goes dry.
+ //
+ while (workList.getCount() != 0)
+ {
+ IRInst* inst = workList.getLast();
+
+ workList.removeLast();
+ workListSet.Remove(inst);
+
+ processInst(inst);
+
+ for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
+ {
+ addToWorkList(child);
+ }
+ }
+ }
+ }
+ };
+
+ void lowerGenerics(
+ IRModule* module)
+ {
+ GenericsLoweringContext context;
+ context.module = module;
+ context.processModule();
+ }
+} // namespace Slang