summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-ir-generics-lowering-context.cpp9
-rw-r--r--source/slang/slang-ir-lower-existential.cpp149
-rw-r--r--source/slang/slang-ir-lower-existential.h13
-rw-r--r--source/slang/slang-ir-lower-generic-call.cpp6
-rw-r--r--source/slang/slang-ir-lower-generic-function.cpp17
-rw-r--r--source/slang/slang-ir-lower-generic-function.h7
-rw-r--r--source/slang/slang-ir-lower-generic-type.cpp5
-rw-r--r--source/slang/slang-ir-lower-generic-type.h3
-rw-r--r--source/slang/slang-ir-lower-generics.cpp19
-rw-r--r--source/slang/slang.vcxproj2
-rw-r--r--source/slang/slang.vcxproj.filters6
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>