summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2020-06-26 11:59:33 -0700
committerGitHub <noreply@github.com>2020-06-26 11:59:33 -0700
commit3e8bdb60afb5b0c0a53ce06d1dbbc429988f5885 (patch)
tree03f379d064f5e4df3423824140fad897b8a688e7 /source/slang
parentd084f632a136354dd12952183994240b459240ee (diff)
parent4e443984065552cc2f648ae2fae9e49a4ef21107 (diff)
Merge pull request #1408 from csyonghe/dyndispatch2
Dynamic dispatch for generic interface requirements and `associatedtype`
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-emit-c-like.cpp27
-rw-r--r--source/slang/slang-emit-cpp.cpp109
-rw-r--r--source/slang/slang-emit-cpp.h2
-rw-r--r--source/slang/slang-emit.cpp3
-rw-r--r--source/slang/slang-ir-inst-defs.h18
-rw-r--r--source/slang/slang-ir-insts.h31
-rw-r--r--source/slang/slang-ir-link.cpp8
-rw-r--r--source/slang/slang-ir-lower-generics.cpp191
-rw-r--r--source/slang/slang-ir-specialize.cpp5
-rw-r--r--source/slang/slang-ir.cpp38
-rw-r--r--source/slang/slang-ir.h31
-rw-r--r--source/slang/slang-lower-to-ir.cpp296
12 files changed, 571 insertions, 188 deletions
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index 3438fd3f4..b1a664ade 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -203,7 +203,7 @@ void CLikeSourceEmitter::emitSimpleType(IRType* type)
case kIROp_HalfType: return UnownedStringSlice("half");
case kIROp_FloatType: return UnownedStringSlice("float");
- case kIROp_DoubleType: return UnownedStringSlice("double");
+ case kIROp_DoubleType: return UnownedStringSlice("double");
default: return UnownedStringSlice();
}
}
@@ -236,9 +236,9 @@ List<IRWitnessTableEntry*> CLikeSourceEmitter::getSortedWitnessTableEntries(IRWi
// Get a sorted list of entries using RequirementKeys defined in `interfaceType`.
for (UInt i = 0; i < interfaceType->getOperandCount(); i++)
{
- auto reqKey = cast<IRStructKey>(interfaceType->getOperand(i));
+ auto reqEntry = cast<IRInterfaceRequirementEntry>(interfaceType->getOperand(i));
IRWitnessTableEntry* entry = nullptr;
- if (witnessTableEntryDictionary.TryGetValue(reqKey, entry))
+ if (witnessTableEntryDictionary.TryGetValue(reqEntry->getRequirementKey(), entry))
{
sortedWitnessTableEntries.add(entry);
}
@@ -305,7 +305,8 @@ void CLikeSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable)
void CLikeSourceEmitter::emitInterface(IRInterfaceType* interfaceType)
{
SLANG_UNUSED(interfaceType);
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "Unimplemented emit: IROpInterfaceType.");
+ // By default, don't emit anything for interface types.
+ // This behavior is overloaded by concrete emitters.
}
void CLikeSourceEmitter::emitTypeImpl(IRType* type, const StringSliceLoc* nameAndLoc)
@@ -1962,6 +1963,10 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
are hashed with 'getStringHash' */
break;
+ case kIROp_undefined:
+ m_writer->emit(getName(inst));
+ break;
+
case kIROp_IntLit:
case kIROp_FloatLit:
case kIROp_BoolLit:
@@ -2285,7 +2290,6 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
m_writer->emit(")");
}
break;
-
default:
diagnoseUnhandledInst(inst);
break;
@@ -3554,6 +3558,11 @@ void CLikeSourceEmitter::emitGlobalInst(IRInst* inst)
are hashed with 'getStringHash' */
break;
+ case kIROp_InterfaceRequirementEntry:
+ // Don't emit anything for interface requirement at global level.
+ // They are handled in `emitInterface`.
+ break;
+
case kIROp_Func:
emitFunc((IRFunc*) inst);
break;
@@ -3610,6 +3619,10 @@ void CLikeSourceEmitter::ensureInstOperandsRec(ComputeEmitActionsContext* ctx, I
ensureInstOperand(ctx, inst->getFullType());
UInt operandCount = inst->operandCount;
+ auto requiredLevel = EmitAction::Definition;
+ if (inst->op == kIROp_InterfaceType)
+ requiredLevel = EmitAction::ForwardDeclaration;
+
for(UInt ii = 0; ii < operandCount; ++ii)
{
// TODO: there are some special cases we can add here,
@@ -3621,7 +3634,7 @@ void CLikeSourceEmitter::ensureInstOperandsRec(ComputeEmitActionsContext* ctx, I
// Similarly, a `call` instruction only needs the callee
// to be forward-declared, etc.
- ensureInstOperand(ctx, inst->getOperand(ii));
+ ensureInstOperand(ctx, inst->getOperand(ii), requiredLevel);
}
for(auto child : inst->getDecorationsAndChildren())
@@ -3641,6 +3654,8 @@ void CLikeSourceEmitter::ensureGlobalInst(ComputeEmitActionsContext* ctx, IRInst
if (!m_compileRequest->allowDynamicCode)
return;
break;
+
+ case kIROp_InterfaceRequirementEntry:
case kIROp_Generic:
return;
diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp
index 4a59f4cf9..7f743d9e0 100644
--- a/source/slang/slang-emit-cpp.cpp
+++ b/source/slang/slang-emit-cpp.cpp
@@ -494,10 +494,15 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S
// struct of function pointers corresponding to the interface type.
auto witnessTableType = static_cast<IRWitnessTableType*>(type);
auto baseType = cast<IRType>(witnessTableType->getOperand(0));
- emitType(baseType);
+ SLANG_RETURN_ON_FAIL(calcTypeName(baseType, target, out));
out << "*";
return SLANG_OK;
}
+ case kIROp_RawPointerType:
+ {
+ out << "void*";
+ return SLANG_OK;
+ }
default:
{
if (isNominalOp(type->op))
@@ -1591,8 +1596,7 @@ void CPPSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable)
{
auto interfaceType = cast<IRInterfaceType>(witnessTable->getOperand(0));
auto witnessTableItems = witnessTable->getChildren();
- List<IRWitnessTableEntry*> sortedWitnessTableEntries = getSortedWitnessTableEntries(witnessTable);
- _maybeEmitWitnessTableTypeDefinition(interfaceType, sortedWitnessTableEntries);
+ _maybeEmitWitnessTableTypeDefinition(interfaceType);
// Define a global variable for the witness table.
m_writer->emit("extern ");
@@ -1613,12 +1617,27 @@ void CPPSourceEmitter::_emitWitnessTableWrappers()
{
for (auto witnessTable : pendingWitnessTableDefinitions)
{
+ auto interfaceType = cast<IRInterfaceType>(witnessTable->getOperand(0));
for (auto child : witnessTable->getChildren())
{
if (auto entry = as<IRWitnessTableEntry>(child))
{
if (auto funcVal = as<IRFunc>(entry->getSatisfyingVal()))
{
+ IRInst* requirementVal = nullptr;
+ for (UInt i = 0; i < interfaceType->getOperandCount(); i++)
+ {
+ if (auto reqEntry = as<IRInterfaceRequirementEntry>(interfaceType->getOperand(i)))
+ {
+ if (reqEntry->getRequirementKey() == entry->getRequirementKey())
+ {
+ requirementVal = reqEntry->getRequirementVal();
+ break;
+ }
+ }
+ }
+ SLANG_ASSERT(requirementVal != nullptr);
+ IRFuncType* requirementFuncType = cast<IRFuncType>(requirementVal);
emitType(funcVal->getResultType());
m_writer->emit(" ");
m_writer->emit(_getWitnessTableWrapperFuncName(funcVal));
@@ -1626,23 +1645,20 @@ void CPPSourceEmitter::_emitWitnessTableWrappers()
// Emit parameter list.
{
bool isFirst = true;
- for (auto param : funcVal->getParams())
+ SLANG_ASSERT(funcVal->getParamCount() == requirementFuncType->getParamCount());
+ auto pp = funcVal->getParams().begin();
+ for (UInt i = 0; i < requirementFuncType->getParamCount(); ++i, ++pp)
{
- if (as<IRTypeType>(param->getFullType()))
+ auto paramType = requirementFuncType->getParamType(i);
+
+ if (as<IRTypeType>(paramType))
continue;
if (isFirst)
isFirst = false;
else
m_writer->emit(",");
-
- if (param->findDecoration<IRThisPointerDecoration>())
- {
- m_writer->emit("void* ");
- m_writer->emit(getName(param));
- continue;
- }
- emitSimpleFuncParamImpl(param);
+ emitParamType(paramType, getName(*pp));
}
}
m_writer->emit(")\n{\n");
@@ -1653,8 +1669,13 @@ void CPPSourceEmitter::_emitWitnessTableWrappers()
// Emit argument list.
{
bool isFirst = true;
- for (auto param : funcVal->getParams())
+ UInt paramIndex = 0;
+ for (auto defParamIter = funcVal->getParams().begin();
+ defParamIter!=funcVal->getParams().end();
+ ++defParamIter, ++paramIndex)
{
+ auto param = *defParamIter;
+ auto reqParamType = requirementFuncType->getParamType(paramIndex);
if (as<IRTypeType>(param->getFullType()))
continue;
@@ -1663,7 +1684,8 @@ void CPPSourceEmitter::_emitWitnessTableWrappers()
else
m_writer->emit(", ");
- if (param->findDecoration<IRThisPointerDecoration>())
+ if (reqParamType->op == kIROp_RawPointerType &&
+ param->getFullType()->op != kIROp_RawPointerType)
{
m_writer->emit("*static_cast<");
emitType(param->getFullType());
@@ -1747,51 +1769,46 @@ void CPPSourceEmitter::emitInterface(IRInterfaceType* interfaceType)
/// acoording to the order defined by `interfaceType`.
///
void CPPSourceEmitter::_maybeEmitWitnessTableTypeDefinition(
- IRInterfaceType* interfaceType,
- const List<IRWitnessTableEntry*>& sortedWitnessTableEntries)
+ IRInterfaceType* interfaceType)
{
m_writer->emit("struct ");
emitSimpleType(interfaceType);
m_writer->emit("\n{\n");
m_writer->indent();
- for (Index i = 0; i < sortedWitnessTableEntries.getCount(); i++)
+ for (UInt i = 0; i < interfaceType->getOperandCount(); i++)
{
- auto entry = sortedWitnessTableEntries[i];
- if (auto funcVal = as<IRFunc>(entry->satisfyingVal.get()))
+ auto entry = as<IRInterfaceRequirementEntry>(interfaceType->getOperand(i));
+ if (auto funcVal = as<IRFuncType>(entry->getRequirementVal()))
{
emitType(funcVal->getResultType());
m_writer->emit(" (KernelContext::*");
- m_writer->emit(getName(entry->requirementKey.get()));
+ m_writer->emit(getName(entry->getRequirementKey()));
m_writer->emit(")");
m_writer->emit("(");
bool isFirstParam = true;
- for (auto param : funcVal->getParams())
+ for (UInt p = 0; p < funcVal->getParamCount(); p++)
{
+ auto paramType = funcVal->getParamType(p);
+ // Ingore TypeType-typed parameters for now.
+ if (as<IRTypeType>(paramType))
+ continue;
+
if (!isFirstParam)
m_writer->emit(", ");
else
isFirstParam = false;
- if (param->findDecoration<IRThisPointerDecoration>())
- {
- m_writer->emit("void* ");
- m_writer->emit(getName(param));
- continue;
- }
- emitSimpleFuncParamImpl(param);
+
+ emitParamType(paramType, String("param") + String(p));
}
m_writer->emit(");\n");
}
- else if (auto witnessTableVal = as<IRWitnessTable>(entry->getSatisfyingVal()))
+ else if (auto witnessTableType = as<IRWitnessTableType>(entry->getRequirementVal()))
{
- emitType(as<IRType>(witnessTableVal->getOperand(0)));
+ emitType((IRType*)witnessTableType->getConformanceType());
m_writer->emit("* ");
- m_writer->emit(getName(entry->requirementKey.get()));
+ m_writer->emit(getName(entry->getRequirementKey()));
m_writer->emit(";\n");
}
- else
- {
- // TODO: handle other witness table entry types.
- }
}
m_writer->dedent();
m_writer->emit("};\n");
@@ -1990,28 +2007,8 @@ void CPPSourceEmitter::emitSimpleValueImpl(IRInst* inst)
}
}
-static bool isVoidPtrType(IRType* type)
-{
- auto ptrType = as<IRPtrType>(type);
- if (!ptrType) return false;
- return ptrType->getValueType()->op == kIROp_VoidType;
-}
-
void CPPSourceEmitter::emitSimpleFuncParamImpl(IRParam* param)
{
- // Polymorphic types are already translated to void* type in
- // lower-generics pass. However, the current emitting logic will
- // emit "void&" instead of "void*" for pointer types.
- // In the future, we will handle pointer types more properly,
- // and this override logic will not be necessary.
- // For now we special-case this scenario.
- if (param->findDecoration<IRPolymorphicDecoration>() &&
- isVoidPtrType(param->getDataType()))
- {
- m_writer->emit("void* ");
- m_writer->emit(getName(param));
- return;
- }
CLikeSourceEmitter::emitSimpleFuncParamImpl(param);
}
diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h
index 47ba03d70..6f91444a3 100644
--- a/source/slang/slang-emit-cpp.h
+++ b/source/slang/slang-emit-cpp.h
@@ -89,7 +89,7 @@ protected:
virtual SlangResult calcScalarFuncName(HLSLIntrinsic::Op op, IRBasicType* type, StringBuilder& outBuilder);
// Emits a struct of function pointers defined in `interfaceType`.
- void _maybeEmitWitnessTableTypeDefinition(IRInterfaceType* interfaceType, const List<IRWitnessTableEntry*>& sortedWitnessTableEntries);
+ void _maybeEmitWitnessTableTypeDefinition(IRInterfaceType* interfaceType);
void _maybeEmitSpecializedOperationDefinition(const HLSLIntrinsic* specOp);
void _emitForwardDeclarations(const List<EmitAction>& actions);
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index f2552f95d..59b059e91 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -280,7 +280,8 @@ Result linkAndOptimizeIR(
// For targets that supports dynamic dispatch, we need to lower the
// generics / interface types to ordinary functions and types using
// function pointers.
- lowerGenerics(irModule);
+ if (compileRequest->allowDynamicCode)
+ lowerGenerics(irModule);
break;
default:
break;
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 58ff1a79f..85c489528 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -25,6 +25,7 @@ INST(Nop, nop, 0, 0)
INST_RANGE(BasicType, VoidType, AfterBaseType)
INST(StringType, String, 0, 0)
+ INST(RawPointerType, RawPointerType, 0, 0)
/* ArrayTypeBase */
INST(ArrayType, Array, 2, 0)
@@ -164,14 +165,16 @@ INST(Nop, nop, 0, 0)
// `field` instructions.
//
INST(StructType, struct, 0, PARENT)
-INST(InterfaceType, interface, 0, PARENT)
+INST(InterfaceType, interface, 0, 0)
+INST(AssociatedType, associated_type, 0, 0)
+INST(ThisType, this_type, 0, 0)
// A TypeType-typed IRValue represents a IRType.
// It is used to represent a type parameter/argument in a generics.
INST(TypeType, type_t, 0, 0)
// An `IRWitnessTable` has type `WitnessTableType`.
-INST(WitnessTableType, witness_table_t, 0, 0)
+INST(WitnessTableType, witness_table_t, 1, 0)
INST_RANGE(Type, VoidType, WitnessTableType)
@@ -223,6 +226,7 @@ INST(Call, call, 1, 0)
INST(WitnessTableEntry, witness_table_entry, 2, 0)
+INST(InterfaceRequirementEntry, interface_req_entry, 2, 0)
INST(Param, param, 0, 0)
INST(StructField, field, 2, 0)
@@ -507,16 +511,6 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(BindExistentialSlotsDecoration, bindExistentialSlots, 0, 0)
- /// A `[polymorphic]` decoration marks a function parameter that should translate to an abstract type
- /// e.g. (void*) that are casted to actual type before use. For example, a parameter of generic type
- /// is marked `[polymorphic]`, so that the code gen logic can emit it as a `void*` parameter,
- /// allowing the function to be used at sites that are agnostic of the actual object type.
- INST(PolymorphicDecoration, polymorphic, 0, 0)
-
- /// A `[this_ptr]` decoration marks a function parameter that serves as `this` pointer.
- INST(ThisPointerDecoration, this_ptr, 0, 0)
-
-
/// A `[format(f)]` decoration specifies that the format of an image should be `f`
INST(FormatDecoration, format, 1, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index b13d52981..f3a0688a7 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -166,10 +166,6 @@ IR_SIMPLE_DECORATION(VulkanCallablePayloadDecoration)
/// to it.
IR_SIMPLE_DECORATION(VulkanHitAttributesDecoration)
-IR_SIMPLE_DECORATION(PolymorphicDecoration)
-IR_SIMPLE_DECORATION(ThisPointerDecoration)
-
-
struct IRRequireGLSLVersionDecoration : IRDecoration
{
enum { kOp = kIROp_RequireGLSLVersionDecoration };
@@ -413,6 +409,8 @@ struct IRLookupWitnessMethod : IRInst
IRInst* getWitnessTable() { return witnessTable.get(); }
IRInst* getRequirementKey() { return requirementKey.get(); }
+
+ IR_LEAF_ISA(lookup_interface_method)
};
struct IRLookupWitnessTable : IRInst
@@ -1432,6 +1430,11 @@ struct IRWitnessTable : IRInst
return IRInstList<IRWitnessTableEntry>(getChildren());
}
+ IRInst* getConformanceType()
+ {
+ return getOperand(0);
+ }
+
IR_LEAF_ISA(WitnessTable)
};
@@ -1571,6 +1574,10 @@ struct IRBuilder
IRBasicType* getBoolType();
IRBasicType* getIntType();
IRStringType* getStringType();
+ IRAssociatedType* getAssociatedType();
+ IRThisType* getThisType();
+ IRRawPointerType* getRawPointerType();
+
IRBasicBlockType* getBasicBlockType();
IRWitnessTableType* getWitnessTableType(IRType* baseType);
@@ -1800,7 +1807,7 @@ struct IRBuilder
IRType* valueType);
IRGlobalParam* createGlobalParam(
IRType* valueType);
-
+
/// Creates an IRWitnessTable value.
/// @param baseType: The comformant-to type of this witness.
IRWitnessTable* createWitnessTable(IRType* baseType);
@@ -1809,6 +1816,10 @@ struct IRBuilder
IRInst* requirementKey,
IRInst* satisfyingVal);
+ IRInterfaceRequirementEntry* createInterfaceRequirementEntry(
+ IRInst* requirementKey,
+ IRInst* requirementVal);
+
// Create an initially empty `struct` type.
IRStructType* createStructType();
@@ -2160,16 +2171,6 @@ struct IRBuilder
addDecoration(value, kIROp_LoopControlDecoration, getIntValue(getIntType(), IRIntegerValue(mode)));
}
- void addPolymorphicDecoration(IRInst* value)
- {
- addDecoration(value, kIROp_PolymorphicDecoration);
- }
-
- void addThisPointerDecoration(IRInst* value)
- {
- addDecoration(value, kIROp_ThisPointerDecoration);
- }
-
void addSemanticDecoration(IRInst* value, UnownedStringSlice const& text, int index = 0)
{
addDecoration(value, kIROp_SemanticDecoration, getStringValue(text), getIntValue(getIntType(), index));
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index 3f51aa876..f80f97aff 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -228,6 +228,7 @@ IRInst* IRSpecContext::maybeCloneValue(IRInst* originalValue)
case kIROp_StructKey:
case kIROp_GlobalGenericParam:
case kIROp_WitnessTable:
+ case kIROp_InterfaceType:
case kIROp_TaggedUnionType:
return cloneGlobalValue(this, originalValue);
@@ -607,8 +608,7 @@ IRInterfaceType* cloneInterfaceTypeImpl(
auto clonedInterface = builder->createInterfaceType(originalInterface->getOperandCount(), nullptr);
for (UInt i = 0; i < originalInterface->getOperandCount(); i++)
{
- auto clonedKey = findClonedValue(context, originalInterface->getOperand(i));
- SLANG_ASSERT(clonedKey);
+ auto clonedKey = cloneValue(context, originalInterface->getOperand(i));
clonedInterface->setOperand(i, clonedKey);
}
cloneSimpleGlobalValueImpl(context, originalInterface, originalValues, clonedInterface);
@@ -628,6 +628,7 @@ void cloneGlobalValueWithCodeCommon(
cloneDecorations(context, clonedValue, originalValue);
cloneExtraDecorations(context, clonedValue, originalValues);
+ clonedValue->setFullType((IRType*)cloneValue(context, originalValue->getFullType()));
// We will walk through the blocks of the function, and clone each of them.
//
@@ -1152,7 +1153,6 @@ IRInst* cloneGlobalValueImpl(
return clonedValue;
}
-
/// Clone a global value, which has the given `originalLinkage`.
///
/// The `originalVal` is a known global IR value with that linkage, if one is available.
@@ -1216,7 +1216,7 @@ IRInst* cloneGlobalValueWithLinkage(
for(IRSpecSymbol* ss = sym; ss; ss = ss->nextWithSameName )
{
IRInst* newVal = ss->irGlobalValue;
- if(isBetterForTarget(context, newVal, bestVal))
+ if (isBetterForTarget(context, newVal, bestVal))
bestVal = newVal;
}
diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp
index f6340a633..774836e29 100644
--- a/source/slang/slang-ir-lower-generics.cpp
+++ b/source/slang/slang-ir-lower-generics.cpp
@@ -16,6 +16,7 @@ namespace Slang
IRModule* module;
Dictionary<IRInst*, IRInst*> loweredGenericFunctions;
+ HashSet<IRInterfaceType*> loweredInterfaceTypes;
SharedIRBuilder sharedBuilderStorage;
@@ -45,6 +46,21 @@ namespace Slang
workListSet.Add(inst);
}
+ bool isPolymorphicType(IRInst* typeInst)
+ {
+ if (as<IRParam>(typeInst) && as<IRTypeType>(typeInst->getFullType()))
+ return true;
+ switch (typeInst->op)
+ {
+ case kIROp_ThisType:
+ case kIROp_AssociatedType:
+ case kIROp_InterfaceType:
+ return true;
+ default:
+ return false;
+ }
+ }
+
IRInst* lowerGenericFunction(IRInst* genericValue)
{
IRInst* result = nullptr;
@@ -64,6 +80,7 @@ namespace Slang
builder.sharedBuilder = &sharedBuilderStorage;
builder.setInsertBefore(genericParent);
auto loweredFunc = cloneInstAndOperands(&cloneEnv, &builder, func);
+ loweredFunc->setFullType(lowerGenericFuncType(&builder, cast<IRGeneric>(genericParent->getFullType())));
List<IRInst*> clonedParams;
for (auto genericParam : genericParent->getParams())
{
@@ -82,15 +99,115 @@ namespace Slang
// Turn generic parameters into void pointers.
for (auto param : cast<IRFunc>(loweredFunc)->getParams())
{
- if (param->findDecoration<IRPolymorphicDecoration>())
+ if (isPolymorphicType(param->getFullType()))
{
- param->setFullType(builder.getPtrType(builder.getVoidType()));
+ param->setFullType(builder.getRawPointerType());
}
}
addToWorkList(loweredFunc);
return loweredFunc;
}
+ IRType* lowerGenericFuncType(IRBuilder* builder, IRGeneric* genericVal)
+ {
+ List<IRInst*> genericParamTypes;
+ for (auto genericParam : genericVal->getParams())
+ {
+ if (isPolymorphicType(genericParam->getFullType()))
+ {
+ genericParamTypes.add(builder->getRawPointerType());
+ }
+ else
+ {
+ genericParamTypes.add(genericParam->getFullType());
+ }
+ }
+
+ auto innerType = (IRFuncType*)lowerFuncType(
+ builder,
+ cast<IRFuncType>(findGenericReturnVal(genericVal)),
+ genericParamTypes.getCount());
+
+ for (int i = 0; i < genericParamTypes.getCount(); i++)
+ {
+ innerType->setOperand(
+ innerType->getOperandCount() - genericParamTypes.getCount() + i,
+ genericParamTypes[i]);
+ }
+
+ return innerType;
+ }
+
+ IRType* lowerFuncType(IRBuilder* builder, IRFuncType* funcType, UInt additionalParamCount = 0)
+ {
+ List<IRInst*> newOperands;
+ bool translated = false;
+ for (UInt i = 0; i < funcType->getOperandCount(); i++)
+ {
+ auto paramType = funcType->getOperand(i);
+ if (isPolymorphicType(paramType))
+ {
+ newOperands.add(builder->getRawPointerType());
+ translated = true;
+ }
+ else if (paramType->op == kIROp_Specialize)
+ {
+ // TODO: handle static specialized type here.
+ // For now treat all specialized types as dynamic.
+ // In the future, we need to turn things like Array<IDynamic> into Array<void*>.
+ newOperands.add(builder->getRawPointerType());
+ translated = true;
+ }
+ else
+ {
+ newOperands.add(paramType);
+ }
+ }
+ if (!translated && additionalParamCount == 0)
+ return funcType;
+ for (UInt i = 0; i < additionalParamCount; i++)
+ {
+ newOperands.add(nullptr);
+ }
+ auto newFuncType = builder->getFuncType(
+ newOperands.getCount() - 1,
+ (IRType**)(newOperands.begin() + 1),
+ (IRType*)newOperands[0]);
+
+ IRCloneEnv cloneEnv;
+ cloneInstDecorationsAndChildren(&cloneEnv, &sharedBuilderStorage, funcType, newFuncType);
+ return newFuncType;
+ }
+
+ IRInterfaceType* maybeLowerInterfaceType(IRInterfaceType* interfaceType)
+ {
+ if (loweredInterfaceTypes.Contains(interfaceType))
+ return interfaceType;
+
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedBuilderStorage;
+ builder.setInsertBefore(interfaceType);
+
+ // Translate IRFuncType in interface requirements.
+ for (UInt i = 0; i < interfaceType->getOperandCount(); i++)
+ {
+ if (auto entry = as<IRInterfaceRequirementEntry>(interfaceType->getOperand(i)))
+ {
+ if (auto funcType = as<IRFuncType>(entry->getRequirementVal()))
+ {
+ entry->setRequirementVal(lowerFuncType(&builder, funcType));
+ }
+ else if (auto genericFuncType = as<IRGeneric>(entry->getRequirementVal()))
+ {
+ entry->setRequirementVal(lowerGenericFuncType(&builder, genericFuncType));
+ }
+ }
+ }
+
+ loweredInterfaceTypes.Add(interfaceType);
+ return interfaceType;
+ }
+
void processInst(IRInst* inst)
{
if (auto callInst = as<IRCall>(inst))
@@ -98,26 +215,55 @@ namespace Slang
// If we see a call(specialize(gFunc, Targs), args),
// translate it into call(gFunc, args, Targs).
auto funcOperand = callInst->getOperand(0);
+ IRInst* loweredFunc = nullptr;
if (auto specializeInst = as<IRSpecialize>(funcOperand))
{
- auto loweredFunc = lowerGenericFunction(specializeInst->getOperand(0));
- if (loweredFunc == specializeInst->getOperand(0))
+ auto funcToSpecialize = specializeInst->getOperand(0);
+ List<IRType*> paramTypes;
+ if (auto interfaceLookup = as<IRLookupWitnessMethod>(funcToSpecialize))
{
- // This is an intrinsic function, don't transform.
- return;
+ // The callee is a result of witness table lookup, we will only
+ // translate the call.
+ IRInst* callee = nullptr;
+ auto witnessTableType = cast<IRWitnessTableType>(interfaceLookup->getWitnessTable()->getFullType());
+ auto interfaceType = maybeLowerInterfaceType(cast<IRInterfaceType>(witnessTableType->getConformanceType()));
+ for (UInt i = 0; i < interfaceType->getOperandCount(); i++)
+ {
+ auto entry = cast<IRInterfaceRequirementEntry>(interfaceType->getOperand(i));
+ if (entry->getRequirementKey() == interfaceLookup->getOperand(1))
+ {
+ callee = entry->getRequirementVal();
+ break;
+ }
+ }
+ auto funcType = cast<IRFuncType>(callee);
+ for (UInt i = 0; i < funcType->getParamCount(); i++)
+ paramTypes.add(funcType->getParamType(i));
+ loweredFunc = funcToSpecialize;
+ }
+ else
+ {
+ loweredFunc = lowerGenericFunction(specializeInst->getOperand(0));
+ if (loweredFunc == specializeInst->getOperand(0))
+ {
+ // This is an intrinsic function, don't transform.
+ return;
+ }
+ for (auto param : as<IRFunc>(loweredFunc)->getParams())
+ paramTypes.add(param->getDataType());
}
+
IRBuilder builderStorage;
auto builder = &builderStorage;
builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(inst);
List<IRInst*> args;
- auto pp = as<IRFunc>(loweredFunc)->getParams().begin();
- auto voidPtrType = builder->getPtrType(builder->getVoidType());
+ auto rawPtrType = builder->getRawPointerType();
for (UInt i = 0; i < callInst->getArgCount(); i++)
{
auto arg = callInst->getArg(i);
- if ((*pp)->getDataType() == voidPtrType &&
- arg->getDataType() != voidPtrType)
+ if (paramTypes[i] == rawPtrType &&
+ arg->getDataType() != rawPtrType)
{
// We are calling a generic function that with an argument of
// concrete type. We need to convert this argument o void*.
@@ -128,11 +274,10 @@ namespace Slang
// what we needed. For now we use another instruction here
// to keep changes minimal.
arg = builder->emitGetAddress(
- voidPtrType,
+ rawPtrType,
arg);
}
args.add(arg);
- ++pp;
}
for (UInt i = 0; i < specializeInst->getArgCount(); i++)
args.add(specializeInst->getArg(i));
@@ -141,6 +286,28 @@ namespace Slang
callInst->removeAndDeallocate();
}
}
+ else if (auto witnessTable = as<IRWitnessTable>(inst))
+ {
+ // Lower generic functions in witness table.
+ for (auto child : witnessTable->getChildren())
+ {
+ auto entry = as<IRWitnessTableEntry>(child);
+ if (!entry)
+ continue;
+ if (auto genericVal = as<IRGeneric>(entry->getSatisfyingVal()))
+ {
+ if (findGenericReturnVal(genericVal)->op == kIROp_Func)
+ {
+ auto loweredFunc = lowerGenericFunction(genericVal);
+ entry->satisfyingVal.set(loweredFunc);
+ }
+ }
+ }
+ }
+ else if (auto interfaceType = as<IRInterfaceType>(inst))
+ {
+ maybeLowerInterfaceType(interfaceType);
+ }
}
void processModule()
diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp
index cf475f1ff..3acb34c87 100644
--- a/source/slang/slang-ir-specialize.cpp
+++ b/source/slang/slang-ir-specialize.cpp
@@ -416,6 +416,11 @@ struct SpecializationContext
case kIROp_BindExistentialsType:
break;
+ // An interface type is always fully specialized.
+ case kIROp_InterfaceType:
+ markInstAsFullySpecialized(inst);
+ break;
+
case kIROp_Specialize:
// The `specialize` instruction is a bit sepcial,
// because it is possible to have a `specialize`
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 77011b569..ef5ecb959 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -1408,10 +1408,7 @@ namespace Slang
inst->op = op;
- if (type)
- {
- inst->typeUse.init(inst, type);
- }
+ inst->typeUse.init(inst, type);
maybeSetSourceLoc(builder, inst);
@@ -1423,6 +1420,10 @@ namespace Slang
{
operand->init(inst, fixedArgs[aa]);
}
+ else
+ {
+ operand->init(inst, nullptr);
+ }
operand++;
}
@@ -2194,6 +2195,21 @@ namespace Slang
return (IRStringType*)getType(kIROp_StringType);
}
+ IRAssociatedType* IRBuilder::getAssociatedType()
+ {
+ return (IRAssociatedType*)getType(kIROp_AssociatedType);
+ }
+
+ IRThisType* IRBuilder::getThisType()
+ {
+ return (IRThisType*)getType(kIROp_ThisType);
+ }
+
+ IRRawPointerType* IRBuilder::getRawPointerType()
+ {
+ return (IRRawPointerType*)getType(kIROp_RawPointerType);
+ }
+
IRBasicBlockType* IRBuilder::getBasicBlockType()
{
return (IRBasicBlockType*)getType(kIROp_BasicBlockType);
@@ -2811,6 +2827,20 @@ namespace Slang
return entry;
}
+ IRInterfaceRequirementEntry* IRBuilder::createInterfaceRequirementEntry(
+ IRInst* requirementKey,
+ IRInst* requirementVal)
+ {
+ IRInterfaceRequirementEntry* entry = createInst<IRInterfaceRequirementEntry>(
+ this,
+ kIROp_InterfaceRequirementEntry,
+ nullptr,
+ requirementKey,
+ requirementVal);
+ addGlobalValue(this, entry);
+ return entry;
+ }
+
IRStructType* IRBuilder::createStructType()
{
IRStructType* structType = createInst<IRStructType>(
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 3c9a15650..f3eccad25 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -458,6 +458,7 @@ struct IRInst
void setOperand(UInt index, IRInst* value)
{
+ SLANG_ASSERT(getOperands()[index].user != nullptr);
getOperands()[index].set(value);
}
@@ -1104,12 +1105,16 @@ struct IRPtrTypeBase : IRType
SIMPLE_IR_TYPE(PtrType, PtrTypeBase)
SIMPLE_IR_TYPE(RefType, PtrTypeBase)
-
SIMPLE_IR_PARENT_TYPE(OutTypeBase, PtrTypeBase)
SIMPLE_IR_TYPE(OutType, OutTypeBase)
SIMPLE_IR_TYPE(InOutType, OutTypeBase)
SIMPLE_IR_TYPE(ExistentialBoxType, PtrTypeBase)
+struct IRRawPointerType : IRType
+{
+ IR_LEAF_ISA(RawPointerType)
+};
+
struct IRGlobalHashedStringLiterals : IRInst
{
IR_LEAF_ISA(GlobalHashedStringLiterals)
@@ -1190,6 +1195,26 @@ struct IRStructType : IRType
IR_LEAF_ISA(StructType)
};
+struct IRAssociatedType : IRType
+{
+ IR_LEAF_ISA(AssociatedType)
+};
+
+struct IRThisType : IRType
+{
+ IR_LEAF_ISA(ThisType)
+};
+
+struct IRInterfaceRequirementEntry : IRInst
+{
+ IRInst* getRequirementKey() { return getOperand(0); }
+ IRInst* getRequirementVal() { return getOperand(1); }
+ void setRequirementKey(IRInst* val) { setOperand(0, val); }
+ void setRequirementVal(IRInst* val) { setOperand(1, val); }
+
+ IR_LEAF_ISA(InterfaceRequirementEntry);
+};
+
struct IRInterfaceType : IRType
{
IR_LEAF_ISA(InterfaceType)
@@ -1207,6 +1232,10 @@ struct IRTypeType : IRType
struct IRWitnessTableType : IRType
{
+ IRInst* getConformanceType()
+ {
+ return getOperand(0);
+ }
IR_LEAF_ISA(WitnessTableType);
};
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index ea04ea85c..58f23b0c8 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -380,6 +380,9 @@ struct IRGenContext
// might be insufficient.
LoweredValInfo thisVal;
+ // The IRType value to lower into for `ThisType`.
+ IRInst* thisType = nullptr;
+
explicit IRGenContext(SharedIRGenContext* inShared, ASTBuilder* inAstBuilder)
: shared(inShared)
, astBuilder(inAstBuilder)
@@ -401,6 +404,18 @@ struct IRGenContext
{
return shared->m_mainModuleDecl;
}
+
+ LoweredValInfo* findLoweredDecl(Decl* decl)
+ {
+ IRGenEnv* envToFindIn = env;
+ while (envToFindIn)
+ {
+ if (auto rs = envToFindIn->mapDeclToValue.TryGetValue(decl))
+ return rs;
+ envToFindIn = envToFindIn->outer;
+ }
+ return nullptr;
+ }
};
void setGlobalValue(SharedIRGenContext* sharedContext, Decl* decl, LoweredValInfo value)
@@ -986,6 +1001,12 @@ IRStructKey* getInterfaceRequirementKey(
IRGenContext* context,
Decl* requirementDecl)
{
+ // TODO: this special case logic can be removed if we also clean up `doesGenericSignatureMatchRequirement`
+ // Currently `doesGenericSignatureMatchRequirement` will use the inner func decl as the key
+ // in AST WitnessTable. Therefore we need to match this behavior by always using the inner
+ // decl as the requirement key.
+ if (auto genericDecl = as<GenericDecl>(requirementDecl))
+ return getInterfaceRequirementKey(context, genericDecl->inner);
IRStructKey* requirementKey = nullptr;
if(context->shared->interfaceRequirementKeys.TryGetValue(requirementDecl, requirementKey))
{
@@ -1035,7 +1056,7 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
{
return emitDeclRef(context, val->declRef,
context->irBuilder->getWitnessTableType(
- lowerType(context, DeclRefType::create(context->astBuilder, val->declRef))));
+ lowerType(context, val->sup)));
}
LoweredValInfo visitTransitiveSubtypeWitness(
@@ -1057,7 +1078,7 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
// to reflect the right constraints.
return LoweredValInfo::simple(getBuilder()->emitLookupInterfaceMethodInst(
- nullptr,
+ getBuilder()->getWitnessTableType(lowerType(context, val->sup)),
baseWitnessTable,
requirementKey));
}
@@ -1568,6 +1589,8 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
//
// For now we punt and emit the `ThisType` of an interface `IFoo` as `IFoo`.
//
+ if (context->thisType != nullptr)
+ return LoweredValInfo::simple(context->thisType);
return emitDeclRef(context, type->interfaceDeclRef, getBuilder()->getTypeKind());
}
@@ -4450,7 +4473,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
auto type = lowerType(subContext, decl->type.type);
- return LoweredValInfo::simple(finishOuterGenerics(subBuilder, type));
+ return LoweredValInfo::simple(finishOuterGenerics(subBuilder, type, outerGeneric));
}
LoweredValInfo visitGenericTypeParamDecl(GenericTypeParamDecl* /*decl*/)
@@ -4660,7 +4683,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
NestedContext nested(this);
auto subBuilder = nested.getBuilder();
auto subContext = nested.getContext();
- emitOuterGenerics(subContext, inheritanceDecl, inheritanceDecl);
+ auto outerGeneric = emitOuterGenerics(subContext, inheritanceDecl, inheritanceDecl);
// Lower the super-type to force its declaration to be lowered.
//
@@ -4689,7 +4712,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
irWitnessTable->moveToEnd();
- return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irWitnessTable));
+ return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irWitnessTable, outerGeneric));
}
LoweredValInfo visitDeclGroup(DeclGroup* declGroup)
@@ -5054,6 +5077,8 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
subContextStorage.irBuilder = &subBuilderStorage;
subContextStorage.env = &subEnvStorage;
+
+ subContextStorage.thisType = outerContext->thisType;
}
IRBuilder* getBuilder() { return &subBuilderStorage; }
@@ -5090,7 +5115,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
auto subBuilder = nestedContext.getBuilder();
auto subContext = nestedContext.getContext();
subBuilder->setInsertInto(subBuilder->getModule()->getModuleInst());
- emitOuterGenerics(subContext, decl, decl);
+ auto outerGeneric = emitOuterGenerics(subContext, decl, decl);
IRType* subVarType = lowerType(subContext, decl->getType());
@@ -5191,7 +5216,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
irGlobal->moveToEnd();
- finishOuterGenerics(subBuilder, irGlobal);
+ finishOuterGenerics(subBuilder, irGlobal, outerGeneric);
return globalVal;
}
@@ -5275,34 +5300,95 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// a witness table for the interface type's conformance
// to its own interface.
//
- List<IRStructKey*> requirementKeys;
- for (auto requirementDecl : decl->members)
+ NestedContext nestedContext(this);
+ auto subBuilder = nestedContext.getBuilder();
+ auto subContext = nestedContext.getContext();
+
+ // Emit any generics that should wrap the actual type.
+ auto outerGeneric = emitOuterGenerics(subContext, decl, decl);
+
+ // Setup subContext for proper lowering `ThisType`, associated types and
+ // the interface decl's self reference.
+ subContext->thisType = getBuilder()->getThisType();
+
+ for (auto member : decl->members)
{
- requirementKeys.add(getInterfaceRequirementKey(requirementDecl));
+ if (as<AssocTypeDecl>(member))
+ {
+ subContext->env->mapDeclToValue[member] = getBuilder()->getAssociatedType();
+ }
+ }
+ // First, compute the number of requirement entries that will be included in this
+ // interface type.
+ UInt operandCount = 0;
+ for (auto requirementDecl : decl->members)
+ {
+ operandCount++;
// As a special case, any type constraints placed
// on an associated type will *also* need to be turned
// into requirement keys for this interface.
if (auto associatedTypeDecl = as<AssocTypeDecl>(requirementDecl))
{
- for (auto constraintDecl : associatedTypeDecl->getMembersOfType<TypeConstraintDecl>())
- {
- requirementKeys.add(getInterfaceRequirementKey(constraintDecl));
- }
+ operandCount += associatedTypeDecl->getMembersOfType<TypeConstraintDecl>().getCount();
}
}
+ // Allocate an IRInterfaceType with the `operandCount` operands.
+ IRInterfaceType* irInterface = subBuilder->createInterfaceType(operandCount, nullptr);
- NestedContext nestedContext(this);
- auto subBuilder = nestedContext.getBuilder();
- auto subContext = nestedContext.getContext();
+ // Add `irInterface` to decl mapping now to prevent cyclic lowering.
+ setValue(subContext, decl, LoweredValInfo::simple(irInterface));
- // Emit any generics that should wrap the actual type.
- emitOuterGenerics(subContext, decl, decl);
+ UInt entryIndex = 0;
- IRInterfaceType* irInterface = subBuilder->createInterfaceType(
- requirementKeys.getCount(),
- reinterpret_cast<IRInst**>(requirementKeys.getBuffer()));
+ for (auto requirementDecl : decl->members)
+ {
+ auto entry = subBuilder->createInterfaceRequirementEntry(
+ getInterfaceRequirementKey(requirementDecl),
+ nullptr);
+ IRInst* requirementVal = lowerDecl(subContext, requirementDecl).val;
+ if (requirementVal)
+ {
+ auto reqType = requirementVal->getFullType();
+ entry->setRequirementVal(reqType);
+ if (!requirementVal->hasUses())
+ {
+ // Remove lowered `IRFunc`s since we only care about
+ // function types.
+ switch (requirementVal->op)
+ {
+ case kIROp_Func:
+ case kIROp_Generic:
+ requirementVal->removeAndDeallocate();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ irInterface->setOperand(entryIndex, entry);
+ entryIndex++;
+ // Add addtional requirements for type constraints placed
+ // on an associated types.
+ if (auto associatedTypeDecl = as<AssocTypeDecl>(requirementDecl))
+ {
+ for (auto constraintDecl : associatedTypeDecl->getMembersOfType<TypeConstraintDecl>())
+ {
+ auto constraintKey = getInterfaceRequirementKey(constraintDecl);
+ irInterface->setOperand(entryIndex,
+ subBuilder->createInterfaceRequirementEntry(constraintKey,
+ getBuilder()->getWitnessTableType(lowerType(context, constraintDecl->getSup().type))));
+ entryIndex++;
+ }
+ }
+ // Add lowered requirement entry to current decl mapping to prevent
+ // the function requirements from being lowered again when we get to
+ // `ensureAllDeclsRec`.
+ setValue(context, requirementDecl, LoweredValInfo::simple(entry));
+ }
+
+
addNameHint(context, irInterface, decl);
addLinkageDecoration(context, irInterface, decl);
subBuilder->setInsertInto(irInterface);
@@ -5313,8 +5399,8 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
addTargetIntrinsicDecorations(irInterface, decl);
-
- return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irInterface));
+ auto finalVal = finishOuterGenerics(subBuilder, irInterface, outerGeneric);
+ return LoweredValInfo::simple(finalVal);
}
LoweredValInfo visitEnumCaseDecl(EnumCaseDecl* decl)
@@ -5348,7 +5434,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
NestedContext nestedContext(this);
auto subBuilder = nestedContext.getBuilder();
auto subContext = nestedContext.getContext();
- emitOuterGenerics(subContext, decl, decl);
+ auto outerGeneric = emitOuterGenerics(subContext, decl, decl);
// An `enum` declaration will currently lower directly to its "tag"
// type, so that any references to the `enum` become referenes to
@@ -5360,7 +5446,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
IRType* loweredTagType = lowerType(subContext, decl->tagType);
- return LoweredValInfo::simple(finishOuterGenerics(subBuilder, loweredTagType));
+ return LoweredValInfo::simple(finishOuterGenerics(subBuilder, loweredTagType, outerGeneric));
}
LoweredValInfo visitAggTypeDecl(AggTypeDecl* decl)
@@ -5371,6 +5457,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
return LoweredValInfo();
}
+ if (as<AssocTypeDecl>(decl))
+ {
+ return LoweredValInfo::simple(getBuilder()->getAssociatedType());
+ }
+
// Given a declaration of a type, we need to make sure
// to output "witness tables" for any interfaces this
// type has declared conformance to.
@@ -5387,12 +5478,12 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
auto subContext = nestedContext.getContext();
// Emit any generics that should wrap the actual type.
- emitOuterGenerics(subContext, decl, decl);
+ auto outerGeneric = emitOuterGenerics(subContext, decl, decl);
+
IRStructType* irStruct = subBuilder->createStructType();
addNameHint(context, irStruct, decl);
addLinkageDecoration(context, irStruct, decl);
-
subBuilder->setInsertInto(irStruct);
// A `struct` that inherits from another `struct` must start
@@ -5458,7 +5549,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
irStruct->moveToEnd();
addTargetIntrinsicDecorations(irStruct, decl);
- return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irStruct));
+ return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irStruct, outerGeneric));
}
LoweredValInfo lowerMemberVarDecl(VarDecl* fieldDecl)
@@ -5787,24 +5878,25 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
//
IRInst* finishOuterGenerics(
IRBuilder* subBuilder,
- IRInst* val)
+ IRInst* val,
+ IRGeneric* parentGeneric)
{
IRInst* v = val;
- for(;;)
+ while (parentGeneric)
{
- auto parentBlock = as<IRBlock>(v->getParent());
- if (!parentBlock) break;
-
- auto parentGeneric = as<IRGeneric>(parentBlock->getParent());
- if (!parentGeneric) break;
-
- subBuilder->setInsertInto(parentBlock);
+ subBuilder->setInsertInto(parentGeneric->getFirstBlock());
subBuilder->emitReturn(v);
parentGeneric->moveToEnd();
// There might be more outer generics,
// so we need to loop until we run out.
v = parentGeneric;
+ auto parentBlock = as<IRBlock>(v->getParent());
+ if (!parentBlock) break;
+
+ parentGeneric = as<IRGeneric>(parentBlock->getParent());
+ if (!parentGeneric) break;
+
}
return v;
}
@@ -5995,29 +6087,17 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
return as<IRStringLit>(builder->getStringValue(stringLitExpr->value.getUnownedSlice()));
}
- LoweredValInfo lowerFuncDecl(FunctionDeclBase* decl)
+ void _lowerFuncResultAndParameterTypes(
+ ParameterLists& parameterLists,
+ List<IRType*>& paramTypes,
+ IRType*& irResultType,
+ IRBuilder* subBuilder,
+ IRGenContext* subContext,
+ FunctionDeclBase* decl)
{
- // We are going to use a nested builder, because we will
- // change the parent node that things get nested into.
- //
- NestedContext nestedContext(this);
- auto subBuilder = nestedContext.getBuilder();
- auto subContext = nestedContext.getContext();
-
- // The actual `IRFunction` that we emit needs to be nested
- // inside of one `IRGeneric` for every outer `GenericDecl`
- // in the declaration hierarchy.
-
- emitOuterGenerics(subContext, decl, decl);
-
// Collect the parameter lists we will use for our new function.
- ParameterLists parameterLists;
collectParameterLists(decl, &parameterLists, kParameterListCollectMode_Default);
- // TODO: if there are any generic parameters in the collected list, then
- // we need to output an IR function with generic parameters (or a generic
- // with a nested function... the exact representation is still TBD).
-
// In most cases the return type for a declaration can be read off the declaration
// itself, but things get a bit more complicated when we have to deal with
// accessors for subscript declarations (and eventually for properties).
@@ -6036,14 +6116,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
}
- // need to create an IR function here
-
- IRFunc* irFunc = subBuilder->createFunc();
- addNameHint(context, irFunc, decl);
- addLinkageDecoration(context, irFunc, decl);
-
- List<IRType*> paramTypes;
-
for( auto paramInfo : parameterLists.params )
{
IRType* irParamType = lowerType(subContext, paramInfo.type);
@@ -6084,7 +6156,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
paramTypes.add(irParamType);
}
- auto irResultType = lowerType(subContext, declForReturnType->returnType);
+ irResultType = lowerType(subContext, declForReturnType->returnType);
if (auto setterDecl = as<SetterDecl>(decl))
{
@@ -6107,11 +6179,81 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// being accessed, rather than a simple value.
irResultType = subBuilder->getPtrType(irResultType);
}
+ }
+
+ IRFuncType* _lowerFuncTypeImpl(
+ ParameterLists& parameterLists,
+ List<IRType*>& paramTypes,
+ IRType*& irResultType,
+ IRBuilder* builder,
+ IRGenContext* irGenContext,
+ FunctionDeclBase* decl)
+ {
+ _lowerFuncResultAndParameterTypes(
+ parameterLists,
+ paramTypes,
+ irResultType,
+ builder,
+ irGenContext,
+ decl);
- auto irFuncType = subBuilder->getFuncType(
+ auto irFuncType = builder->getFuncType(
paramTypes.getCount(),
paramTypes.getBuffer(),
irResultType);
+
+ return irFuncType;
+ }
+
+ IRInst* lowerFuncType(FunctionDeclBase* decl)
+ {
+ NestedContext nestedContextFuncType(this);
+ auto funcTypeBuilder = nestedContextFuncType.getBuilder();
+ auto funcTypeContext = nestedContextFuncType.getContext();
+
+ auto outerGenerics = emitOuterGenerics(funcTypeContext, decl, decl);
+
+ ParameterLists parameterLists;
+ List<IRType*> paramTypes;
+ IRType* irResultType = nullptr;
+ auto irFuncType = _lowerFuncTypeImpl(
+ parameterLists,
+ paramTypes,
+ irResultType,
+ funcTypeBuilder,
+ funcTypeContext,
+ decl);
+
+ return finishOuterGenerics(funcTypeBuilder, irFuncType, outerGenerics);
+ }
+
+ LoweredValInfo lowerFuncDecl(FunctionDeclBase* decl)
+ {
+ // We are going to use a nested builder, because we will
+ // change the parent node that things get nested into.
+ //
+ NestedContext nestedContextFunc(this);
+ auto subBuilder = nestedContextFunc.getBuilder();
+ auto subContext = nestedContextFunc.getContext();
+
+ auto outerGeneric = emitOuterGenerics(subContext, decl, decl);
+
+ // need to create an IR function here
+
+ IRFunc* irFunc = subBuilder->createFunc();
+ addNameHint(context, irFunc, decl);
+ addLinkageDecoration(context, irFunc, decl);
+
+ ParameterLists parameterLists;
+ List<IRType*> paramTypes;
+ IRType* irResultType = nullptr;
+ auto irFuncType = _lowerFuncTypeImpl(
+ parameterLists,
+ paramTypes,
+ irResultType,
+ subBuilder,
+ subContext,
+ decl);
irFunc->setFullType(irFuncType);
subBuilder->setInsertInto(irFunc);
@@ -6251,14 +6393,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
if (paramInfo.isThisParam)
{
subContext->thisVal = paramVal;
- subBuilder->addThisPointerDecoration(irParam);
- }
-
- // Add a [polymorphic] decoration for generic-typed parameters.
- if (as<IRParam>(irParamType) &&
- as<IRTypeType>(irParamType->getFullType()))
- {
- subBuilder->addPolymorphicDecoration(irParam);
}
}
@@ -6470,7 +6604,17 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// body appear before the function itself in the list
// of global values.
irFunc->moveToEnd();
- return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irFunc));
+
+ // If this function is defined inside an interface, add a reference to the IRFunc from
+ // the interface's type definition.
+ auto finalVal = finishOuterGenerics(subBuilder, irFunc, outerGeneric);
+ if (auto genericVal = as<IRGeneric>(finalVal))
+ {
+ auto funcType = lowerFuncType(decl);
+ genericVal->setFullType((IRType*)funcType);
+ }
+
+ return LoweredValInfo::simple(finalVal);
}
LoweredValInfo visitGenericDecl(GenericDecl * genDecl)