summaryrefslogtreecommitdiff
path: root/source/slang/lower-to-ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/lower-to-ir.cpp')
-rw-r--r--source/slang/lower-to-ir.cpp102
1 files changed, 94 insertions, 8 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index 74ec35fcd..0d39664c8 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -1288,6 +1288,22 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
return lowerGenericIntrinsicType(type, elementType, count);
}
+ IRType* visitExtractExistentialType(ExtractExistentialType* type)
+ {
+ auto declRef = type->declRef;
+ auto existentialType = lowerType(context, GetType(declRef));
+ IRInst* existentialVal = getSimpleVal(context, emitDeclRef(context, declRef, existentialType));
+ return getBuilder()->emitExtractExistentialType(existentialVal);
+ }
+
+ LoweredValInfo visitExtractExistentialSubtypeWitness(ExtractExistentialSubtypeWitness* witness)
+ {
+ auto declRef = witness->declRef;
+ auto existentialType = lowerType(context, GetType(declRef));
+ IRInst* existentialVal = getSimpleVal(context, emitDeclRef(context, declRef, existentialType));
+ return LoweredValInfo::simple(getBuilder()->emitExtractExistentialWitnessTable(existentialVal));
+ }
+
// We do not expect to encounter the following types in ASTs that have
// passed front-end semantic checking.
#define UNEXPECTED_CASE(NAME) IRType* visit##NAME(NAME*) { SLANG_UNEXPECTED(#NAME); UNREACHABLE_RETURN(nullptr); }
@@ -2088,6 +2104,32 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
UNREACHABLE_RETURN(LoweredValInfo());
}
+ LoweredValInfo visitCastToInterfaceExpr(
+ CastToInterfaceExpr* expr)
+ {
+ // We have an expression that is "up-casting" some concrete value
+ // to an existential type (aka interface type), using a subtype witness
+ // (which will lower as a witness table) to show that the conversion
+ // is valid.
+ //
+ // At the IR level, this will become a `makeExistential` instruction,
+ // which collects the above information into a single IR-level value.
+ // A dynamic CPU implementation of Slang might encode an existential
+ // as a "fat pointer" representation, which includes a pointer to
+ // data for the concrete value, plus a pointer to the witness table.
+ //
+ // Note: if/when Slang supports more general existential types, such
+ // as compositions of interface (e.g., `IReadable & IWritable`), then
+ // we should probably extend the AST and IR mechanism here to accept
+ // a sequence of witness tables.
+ //
+ auto existentialType = lowerType(context, expr->type);
+ auto concreteValue = getSimpleVal(context, lowerRValueExpr(context, expr->valueArg));
+ auto witnessTable = lowerSimpleVal(context, expr->witnessArg);
+ auto existentialValue = getBuilder()->emitMakeExistential(existentialType, concreteValue, witnessTable);
+ return LoweredValInfo::simple(existentialValue);
+ }
+
LoweredValInfo subscriptValue(
IRType* type,
LoweredValInfo baseVal,
@@ -2160,6 +2202,27 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
// to be an l-value).
return leftVal;
}
+
+ LoweredValInfo visitLetExpr(LetExpr* expr)
+ {
+ // TODO: deal with the case where we might want to capture
+ // a reference to the bound value...
+
+ auto initVal = lowerLValueExpr(context, expr->decl->initExpr);
+ setGlobalValue(context, expr->decl, initVal);
+ auto bodyVal = lowerSubExpr(expr->body);
+ return bodyVal;
+ }
+
+ LoweredValInfo visitExtractExistentialValueExpr(ExtractExistentialValueExpr* expr)
+ {
+ auto existentialType = lowerType(context, GetType(expr->declRef));
+ auto existentialVal = getSimpleVal(context, emitDeclRef(context, expr->declRef, existentialType));
+
+ auto openedType = lowerType(context, expr->type);
+
+ return LoweredValInfo::simple(getBuilder()->emitExtractExistentialValue(openedType, existentialVal));
+ }
};
struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVisitor>
@@ -2230,7 +2293,6 @@ struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVis
context->shared->extValues.Add(swizzledLValue);
return LoweredValInfo::swizzledLValue(swizzledLValue);
}
-
};
struct RValueExprLoweringVisitor : ExprLoweringVisitorBase<RValueExprLoweringVisitor>
@@ -4220,12 +4282,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
LoweredValInfo visitInterfaceDecl(InterfaceDecl* decl)
{
- // The interface decl is not itself a type in the IR
- // (yet), so the only thing we need to do here is
- // enumerate the requirements that the interface
- // imposes on implementations.
- //
- // These members will turn into the keys that will
+ // The members of an interface will turn into the keys that will
// be used for lookup operations into witness
// tables that promise conformance to the interface.
//
@@ -4254,7 +4311,28 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
}
- return LoweredValInfo();
+
+ NestedContext nestedContext(this);
+ auto subBuilder = nestedContext.getBuilder();
+ auto subContext = nestedContext.getContet();
+
+ // Emit any generics that should wrap the actual type.
+ emitOuterGenerics(subContext, decl, decl);
+
+ IRInterfaceType* irInterface = subBuilder->createInterfaceType();
+ addNameHint(context, irInterface, decl);
+ addLinkageDecoration(context, irInterface, decl);
+ subBuilder->setInsertInto(irInterface);
+
+ // TODO: are there any interface members that should be
+ // nested inside the interface type itself?
+
+ irInterface->moveToEnd();
+
+ addTargetIntrinsicDecorations(irInterface, decl);
+
+
+ return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irInterface));
}
LoweredValInfo visitEnumCaseDecl(EnumCaseDecl* decl)
@@ -5451,6 +5529,14 @@ LoweredValInfo emitDeclRef(
}
else if(auto thisTypeSubst = subst.As<ThisTypeSubstitution>())
{
+ if(decl.Ptr() == thisTypeSubst->interfaceDecl)
+ {
+ // This is a reference to the interface type itself,
+ // through the this-type substitution, so it is really
+ // a reference to the this-type.
+ return lowerType(context, thisTypeSubst->witness->sub);
+ }
+
// Somebody is trying to look up an interface requirement
// "through" some concrete type. We need to lower this decl-ref
// as a lookup of the corresponding member in a witness table.