diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-ir-generics-lowering-context.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-existential.cpp | 149 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-existential.h | 13 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-call.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-function.cpp | 17 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-function.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-type.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-type.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generics.cpp | 19 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 2 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 6 |
11 files changed, 229 insertions, 7 deletions
diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index 9edc81b6a..55e18ebbb 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -157,8 +157,15 @@ namespace Slang return lowerAssociatedType(builder, paramType); } case kIROp_InterfaceType: + { + // An existential type translates into a tuple of (AnyValue, WitnessTable, RTTI*) anyValueSize = getInterfaceAnyValueSize(paramType, paramType->sourceLoc); - return builder->getAnyValueType(anyValueSize); + auto anyValueType = builder->getAnyValueType(anyValueSize); + auto witnessTableType = builder->getWitnessTableType((IRType*)paramType); + auto rttiType = builder->getPtrType(builder->getRTTIType()); + auto tupleType = builder->getTupleType(anyValueType, witnessTableType, rttiType); + return tupleType; + } case kIROp_lookup_interface_method: { auto lookupInterface = static_cast<IRLookupWitnessMethod*>(paramType); 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<IRWitnessTableType>(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<IRTupleType>(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<IRMakeExistential>(inst)) + { + processMakeExistential(makeExistential); + } + else if (auto extractExistentialVal = as<IRExtractExistentialValue>(inst)) + { + processExtractExistentialValue(extractExistentialVal); + } + else if (auto extractExistentialType = as<IRExtractExistentialType>(inst)) + { + processExtractExistentialType(extractExistentialType); + } + else if (auto extractExistentialWitnessTable = as<IRExtractExistentialWitnessTable>(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(); + } +} diff --git a/source/slang/slang-ir-lower-existential.h b/source/slang/slang-ir-lower-existential.h new file mode 100644 index 000000000..19c1f4bc2 --- /dev/null +++ b/source/slang/slang-ir-lower-existential.h @@ -0,0 +1,13 @@ +// slang-ir-lower-existential.h +#pragma once + +namespace Slang +{ + struct SharedGenericsLoweringContext; + + /// Lower existential types and related instructions to Tuple types. + void lowerExistentials( + SharedGenericsLoweringContext* sharedContext); + +} + diff --git a/source/slang/slang-ir-lower-generic-call.cpp b/source/slang/slang-ir-lower-generic-call.cpp index 22599922e..1bc6d6705 100644 --- a/source/slang/slang-ir-lower-generic-call.cpp +++ b/source/slang/slang-ir-lower-generic-call.cpp @@ -1,5 +1,5 @@ -// slang-ir-lower-generic-function.cpp -#include "slang-ir-lower-generic-function.h" +// slang-ir-lower-generic-call.cpp +#include "slang-ir-lower-generic-call.h" #include "slang-ir-generics-lowering-context.h" namespace Slang @@ -203,7 +203,7 @@ namespace Slang else if (auto lookupInst = as<IRLookupWitnessMethod>(callInst->getCallee())) lowerCallToInterfaceMethod(callInst, lookupInst); } - + void processInst(IRInst* inst) { if (auto callInst = as<IRCall>(inst)) diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp index 1d90625a4..360e3cdbb 100644 --- a/source/slang/slang-ir-lower-generic-function.cpp +++ b/source/slang/slang-ir-lower-generic-function.cpp @@ -167,8 +167,9 @@ namespace Slang } } loweredType = builder.createInterfaceType(newEntries.getCount(), (IRInst**)newEntries.getBuffer()); - interfaceType->transferDecorationsTo(loweredType); - interfaceType->replaceUsesWith(loweredType); + IRCloneEnv cloneEnv; + cloneInstDecorationsAndChildren(&cloneEnv, &sharedContext->sharedBuilderStorage, + interfaceType, loweredType); sharedContext->loweredInterfaceTypes.Add(interfaceType, loweredType); sharedContext->mapLoweredInterfaceToOriginal[loweredType] = interfaceType; return loweredType; @@ -272,6 +273,16 @@ namespace Slang } } + void replaceLoweredInterfaceTypes() + { + for (auto lowered : sharedContext->loweredInterfaceTypes) + { + lowered.Key->replaceUsesWith(lowered.Value); + } + // Update hash keys of globalNumberingMap, since the types are modified. + sharedContext->sharedBuilderStorage.deduplicateAndRebuildGlobalNumberingMap(); + } + void processModule() { // We start by initializing our shared IR building state, @@ -303,6 +314,8 @@ namespace Slang } } } + + replaceLoweredInterfaceTypes(); } }; void lowerGenericFunctions(SharedGenericsLoweringContext* sharedContext) diff --git a/source/slang/slang-ir-lower-generic-function.h b/source/slang/slang-ir-lower-generic-function.h index c364cfdd0..b2570e653 100644 --- a/source/slang/slang-ir-lower-generic-function.h +++ b/source/slang/slang-ir-lower-generic-function.h @@ -7,6 +7,13 @@ namespace Slang /// Lower generic and interface-based code to ordinary types and functions using /// dynamic dispatch mechanisms. + /// After this pass, generic type parameters will be lowered into `AnyValue` types, + /// and an existential type I in function signatures will be lowered into + /// `Tuple<AnyValue, WintessTable(I), RTTI*>`. + /// Note that this pass mostly deals with function signatures and interface definitions, + /// and does not modify function bodies. + /// All variable declarations and type uses are handled in `lower-generic-type`, + /// and all call sites are handled in `lower-generic-call`. void lowerGenericFunctions( SharedGenericsLoweringContext* sharedContext); diff --git a/source/slang/slang-ir-lower-generic-type.cpp b/source/slang/slang-ir-lower-generic-type.cpp index c94a4c37e..4ea47a4b2 100644 --- a/source/slang/slang-ir-lower-generic-type.cpp +++ b/source/slang/slang-ir-lower-generic-type.cpp @@ -16,6 +16,10 @@ namespace Slang void processInst(IRInst* inst) { + // If inst is a type itself, keep its type. + if (as<IRType>(inst)) + return; + IRBuilder builderStorage; auto builder = &builderStorage; builder->sharedBuilder = &sharedContext->sharedBuilderStorage; @@ -57,6 +61,7 @@ namespace Slang } } } + sharedContext->sharedBuilderStorage.deduplicateAndRebuildGlobalNumberingMap(); } }; diff --git a/source/slang/slang-ir-lower-generic-type.h b/source/slang/slang-ir-lower-generic-type.h index 6432a494b..f0262dc59 100644 --- a/source/slang/slang-ir-lower-generic-type.h +++ b/source/slang/slang-ir-lower-generic-type.h @@ -5,7 +5,8 @@ namespace Slang { struct SharedGenericsLoweringContext; - /// Lower all references to generic types (ThisType, AssociatedType, etc.) into IRAnyValueType. + /// Lower all references to generic types (ThisType, AssociatedType, etc.) into IRAnyValueType, + /// and existential types into Tuple<AnyValue, WitnessTable(I), Ptr(RTTIType)>. void lowerGenericType( SharedGenericsLoweringContext* sharedContext); diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp index 7df590b23..b00e36ef1 100644 --- a/source/slang/slang-ir-lower-generics.cpp +++ b/source/slang/slang-ir-lower-generics.cpp @@ -3,6 +3,7 @@ #include "slang-ir-any-value-marshalling.h" #include "slang-ir-generics-lowering-context.h" +#include "slang-ir-lower-existential.h" #include "slang-ir-lower-generic-function.h" #include "slang-ir-lower-generic-call.h" #include "slang-ir-lower-generic-type.h" @@ -20,11 +21,29 @@ namespace Slang sharedContext.module = module; sharedContext.sink = sink; + lowerExistentials(&sharedContext); + if (sink->getErrorCount() != 0) + return; + lowerGenericFunctions(&sharedContext); + if (sink->getErrorCount() != 0) + return; + lowerGenericType(&sharedContext); + if (sink->getErrorCount() != 0) + return; + lowerGenericCalls(&sharedContext); + if (sink->getErrorCount() != 0) + return; + generateWitnessTableWrapperFunctions(&sharedContext); + if (sink->getErrorCount() != 0) + return; + generateAnyValueMarshallingFunctions(&sharedContext); + if (sink->getErrorCount() != 0) + return; // We might have generated new temporary variables during lowering. // An SSA pass can clean up unnecessary load/stores. constructSSA(module); diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index 44ea96309..8861413c9 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -241,6 +241,7 @@ <ClInclude Include="slang-ir-layout.h" /> <ClInclude Include="slang-ir-legalize-varying-params.h" /> <ClInclude Include="slang-ir-link.h" /> + <ClInclude Include="slang-ir-lower-existential.h" /> <ClInclude Include="slang-ir-lower-generic-call.h" /> <ClInclude Include="slang-ir-lower-generic-function.h" /> <ClInclude Include="slang-ir-lower-generic-type.h" /> @@ -345,6 +346,7 @@ <ClCompile Include="slang-ir-legalize-types.cpp" /> <ClCompile Include="slang-ir-legalize-varying-params.cpp" /> <ClCompile Include="slang-ir-link.cpp" /> + <ClCompile Include="slang-ir-lower-existential.cpp" /> <ClCompile Include="slang-ir-lower-generic-call.cpp" /> <ClCompile Include="slang-ir-lower-generic-function.cpp" /> <ClCompile Include="slang-ir-lower-generic-type.cpp" /> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index 73caa41ac..a556b5b03 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -174,6 +174,9 @@ <ClInclude Include="slang-ir-link.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-ir-lower-existential.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-ir-lower-generic-call.h"> <Filter>Header Files</Filter> </ClInclude> @@ -482,6 +485,9 @@ <ClCompile Include="slang-ir-link.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-ir-lower-existential.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-ir-lower-generic-call.cpp"> <Filter>Source Files</Filter> </ClCompile> |
