summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-lower-tuple-types.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2020-08-13 12:17:59 -0700
committerGitHub <noreply@github.com>2020-08-13 12:17:59 -0700
commit876968ccadf96ff592061c61855d77c6071f89f5 (patch)
tree7615ff80b7db8540d4a8034e699b3f1e3a58739e /source/slang/slang-ir-lower-tuple-types.cpp
parent09adf10f646f01e177d412ba2d86602a51579b4f (diff)
IR support for Tuple types. (#1492)
* Tuple types. * Fix x86 warning * Improved deduplication Co-authored-by: Tim Foley <tfoleyNV@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-ir-lower-tuple-types.cpp')
-rw-r--r--source/slang/slang-ir-lower-tuple-types.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/source/slang/slang-ir-lower-tuple-types.cpp b/source/slang/slang-ir-lower-tuple-types.cpp
new file mode 100644
index 000000000..814f92283
--- /dev/null
+++ b/source/slang/slang-ir-lower-tuple-types.cpp
@@ -0,0 +1,197 @@
+// slang-ir-lower-tuple-types.cpp
+
+#include "slang-ir-lower-tuple-types.h"
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+
+namespace Slang
+{
+ struct TupleLoweringContext
+ {
+ IRModule* module;
+ DiagnosticSink* sink;
+
+ SharedIRBuilder sharedBuilderStorage;
+
+ List<IRInst*> workList;
+ HashSet<IRInst*> workListSet;
+
+ struct LoweredTupleInfo : public RefObject
+ {
+ IRType* tupleType;
+ IRStructType* structType;
+ List<IRStructField*> fields;
+ };
+ Dictionary<IRInst*, RefPtr<LoweredTupleInfo>> mapLoweredStructToTupleInfo;
+ Dictionary<IRInst*, RefPtr<LoweredTupleInfo>> loweredTuples;
+
+ IRType* maybeLowerTupleType(IRBuilder* builder, IRType* type)
+ {
+ if (auto info = getLoweredTupleType(builder, type))
+ return info->structType;
+ else
+ return type;
+ }
+
+ void appendTypeName(StringBuilder& sb, IRInst* inst)
+ {
+ if (auto name = inst->findDecoration<IRNameHintDecoration>())
+ {
+ sb << name->getName();
+ }
+ }
+
+ LoweredTupleInfo* getLoweredTupleType(IRBuilder* builder, IRInst* type)
+ {
+ if (auto loweredInfo = loweredTuples.TryGetValue(type))
+ return loweredInfo->Ptr();
+ if (auto loweredInfo = mapLoweredStructToTupleInfo.TryGetValue(type))
+ return loweredInfo->Ptr();
+
+ if (!type)
+ return nullptr;
+ if (type->op != kIROp_TupleType)
+ return nullptr;
+
+ RefPtr<LoweredTupleInfo> info = new LoweredTupleInfo();
+ info->tupleType = (IRType*)type;
+ auto structType = builder->createStructType();
+ info->structType = structType;
+ StringBuilder nameSb, fieldNameSb;
+ nameSb << "Tuple";
+ for (UInt i = 0; i < type->getOperandCount(); i++)
+ {
+ auto elementType = maybeLowerTupleType(builder, (IRType*)(type->getOperand(i)));
+ nameSb << "_";
+ appendTypeName(nameSb, elementType);
+ auto key = builder->createStructKey();
+ fieldNameSb.Clear();
+ fieldNameSb << "value" << i;
+ builder->addNameHintDecoration(key, fieldNameSb.getUnownedSlice());
+ auto field = builder->createStructField(structType, key, (IRType*)elementType);
+ info->fields.add(field);
+ }
+ builder->addNameHintDecoration(structType, nameSb.getUnownedSlice());
+ mapLoweredStructToTupleInfo[structType] = info;
+ loweredTuples[type] = info;
+ return info.Ptr();
+ }
+
+ void addToWorkList(
+ IRInst* inst)
+ {
+ 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);
+ }
+
+ void processMakeTuple(IRMakeTuple* inst)
+ {
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+ builder->sharedBuilder = &sharedBuilderStorage;
+ builder->setInsertBefore(inst);
+
+ auto info = getLoweredTupleType(builder, inst->getDataType());
+ auto var = builder->emitVar(info->structType);
+ for (Index i = 0; i < info->fields.getCount(); i++)
+ {
+ SLANG_ASSERT(i < (Index)inst->getOperandCount());
+ auto ptrType = builder->getPtrType(info->fields[i]->getFieldType());
+ auto addr = builder->emitFieldAddress(ptrType, var, info->fields[i]->getKey());
+ builder->emitStore(addr, inst->getOperand((UInt)i));
+ }
+ auto load = builder->emitLoad(var);
+ inst->replaceUsesWith(load);
+ inst->removeAndDeallocate();
+ }
+
+ void processGetTupleElement(IRGetTupleElement* inst)
+ {
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+ builder->sharedBuilder = &sharedBuilderStorage;
+ builder->setInsertBefore(inst);
+
+ auto base = inst->getTuple();
+ auto loweredTupleInfo = getLoweredTupleType(builder, base->getDataType());
+ SLANG_ASSERT(loweredTupleInfo);
+ auto elementIndex = getIntVal(inst->getElementIndex());
+ SLANG_ASSERT((Index)elementIndex < loweredTupleInfo->fields.getCount());
+
+ auto field = loweredTupleInfo->fields[(Index)elementIndex];
+ auto getElement = builder->emitFieldExtract(field->getFieldType(), base, field->getKey());
+ inst->replaceUsesWith(getElement);
+ inst->removeAndDeallocate();
+ }
+
+ void processInst(IRInst* inst)
+ {
+ switch (inst->op)
+ {
+ case kIROp_MakeTuple:
+ processMakeTuple((IRMakeTuple*)inst);
+ break;
+ case kIROp_GetTupleElement:
+ processGetTupleElement((IRGetTupleElement*)inst);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void processModule()
+ {
+ SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
+ sharedBuilder->module = module;
+ sharedBuilder->session = module->session;
+
+ // Deduplicate equivalent types.
+ sharedBuilder->deduplicateAndRebuildGlobalNumberingMap();
+
+ 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);
+ }
+ }
+ }
+
+ // Replace all tuple types with lowered struct types.
+ for (auto kv : loweredTuples)
+ {
+ kv.Key->replaceUsesWith(kv.Value->structType);
+ }
+ }
+ };
+
+ void lowerTuples(IRModule* module, DiagnosticSink* sink)
+ {
+ TupleLoweringContext context;
+ context.module = module;
+ context.sink = sink;
+ context.processModule();
+ }
+}