diff options
| author | Yong He <yonghe@outlook.com> | 2020-08-13 12:17:59 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-13 12:17:59 -0700 |
| commit | 876968ccadf96ff592061c61855d77c6071f89f5 (patch) | |
| tree | 7615ff80b7db8540d4a8034e699b3f1e3a58739e /source/slang/slang-ir-lower-tuple-types.cpp | |
| parent | 09adf10f646f01e177d412ba2d86602a51579b4f (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.cpp | 197 |
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(); + } +} |
