From b37a7770d9781515f70047665d12680a5838406d Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 14 Aug 2020 10:04:32 -0700 Subject: Lower existential types. (#1497) Co-authored-by: Tim Foley --- source/slang/slang-ir-lower-existential.cpp | 149 ++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 source/slang/slang-ir-lower-existential.cpp (limited to 'source/slang/slang-ir-lower-existential.cpp') diff --git a/source/slang/slang-ir-lower-existential.cpp b/source/slang/slang-ir-lower-existential.cpp new file mode 100644 index 000000000..af47a1dfe --- /dev/null +++ b/source/slang/slang-ir-lower-existential.cpp @@ -0,0 +1,149 @@ +// slang-ir-lower-generic-existential.cpp + +#include "slang-ir-lower-existential.h" +#include "slang-ir-generics-lowering-context.h" +#include "slang-ir.h" +#include "slang-ir-insts.h" + +namespace Slang +{ + struct ExistentialLoweringContext + { + SharedGenericsLoweringContext* sharedContext; + + void processMakeExistential(IRMakeExistential* inst) + { + IRBuilder builderStorage; + auto builder = &builderStorage; + builder->sharedBuilder = &sharedContext->sharedBuilderStorage; + builder->setInsertBefore(inst); + + auto value = inst->getWrappedValue(); + auto valueType = sharedContext->lowerType(builder, value->getDataType()); + auto witnessTableType = cast(inst->getWitnessTable()->getDataType()); + auto interfaceType = witnessTableType->getConformanceType(); + auto anyValueSize = sharedContext->getInterfaceAnyValueSize(interfaceType, inst->sourceLoc); + auto anyValueType = builder->getAnyValueType(anyValueSize); + auto rttiType = builder->getPtrType(builder->getRTTIType()); + auto tupleType = builder->getTupleType(anyValueType, witnessTableType, rttiType); + + IRInst* rttiObject = nullptr; + if (valueType->op != kIROp_AnyValueType) + { + rttiObject = sharedContext->maybeEmitRTTIObject(valueType); + rttiObject = builder->emitGetAddress( + builder->getPtrType(builder->getRTTIType()), + rttiObject); + } + else + { + rttiObject = valueType; + } + IRInst* packedValue = value; + if (valueType->op != kIROp_AnyValueType) + packedValue = builder->emitPackAnyValue(anyValueType, value); + IRInst* tupleArgs[] = { packedValue, inst->getWitnessTable(), rttiObject }; + auto tuple = builder->emitMakeTuple(tupleType, 3, tupleArgs); + inst->replaceUsesWith(tuple); + inst->removeAndDeallocate(); + } + + IRInst* extractTupleElement(IRBuilder* builder, IRInst* value, UInt index) + { + auto tupleType = cast(sharedContext->lowerType(builder, value->getDataType())); + auto getElement = builder->emitGetTupleElement( + (IRType*)tupleType->getOperand(index), + value, + index); + return getElement; + } + + void processExtractExistentialElement(IRInst* extractInst, UInt elementId) + { + IRBuilder builderStorage; + auto builder = &builderStorage; + builder->sharedBuilder = &sharedContext->sharedBuilderStorage; + builder->setInsertBefore(extractInst); + + auto element = extractTupleElement(builder, extractInst->getOperand(0), elementId); + extractInst->replaceUsesWith(element); + extractInst->removeAndDeallocate(); + } + + void processExtractExistentialValue(IRExtractExistentialValue* inst) + { + processExtractExistentialElement(inst, 0); + } + + void processExtractExistentialWitnessTable(IRExtractExistentialWitnessTable* inst) + { + processExtractExistentialElement(inst, 1); + } + + void processExtractExistentialType(IRExtractExistentialType* inst) + { + processExtractExistentialElement(inst, 2); + } + + void processInst(IRInst* inst) + { + if (auto makeExistential = as(inst)) + { + processMakeExistential(makeExistential); + } + else if (auto extractExistentialVal = as(inst)) + { + processExtractExistentialValue(extractExistentialVal); + } + else if (auto extractExistentialType = as(inst)) + { + processExtractExistentialType(extractExistentialType); + } + else if (auto extractExistentialWitnessTable = as(inst)) + { + processExtractExistentialWitnessTable(extractExistentialWitnessTable); + } + } + + 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 = &sharedContext->sharedBuilderStorage; + sharedBuilder->module = sharedContext->module; + sharedBuilder->session = sharedContext->module->session; + + sharedContext->addToWorkList(sharedContext->module->getModuleInst()); + + while (sharedContext->workList.getCount() != 0) + { + // We will then iterate until our work list goes dry. + // + while (sharedContext->workList.getCount() != 0) + { + IRInst* inst = sharedContext->workList.getLast(); + + sharedContext->workList.removeLast(); + sharedContext->workListSet.Remove(inst); + + processInst(inst); + + for (auto child = inst->getLastChild(); child; child = child->getPrevInst()) + { + sharedContext->addToWorkList(child); + } + } + } + } + }; + + + void lowerExistentials(SharedGenericsLoweringContext* sharedContext) + { + ExistentialLoweringContext context; + context.sharedContext = sharedContext; + context.processModule(); + } +} -- cgit v1.2.3