diff options
Diffstat (limited to 'source/slang/lower-to-ir.cpp')
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 1755 |
1 files changed, 1098 insertions, 657 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 5f8428698..4f5e8bceb 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -82,8 +82,8 @@ struct SubscriptInfo : ExtendedValueInfo struct BoundSubscriptInfo : ExtendedValueInfo { DeclRef<SubscriptDecl> declRef; - RefPtr<Type> type; - List<IRInst*> args; + IRType* type; + List<IRInst*> args; }; // Some cases of `ExtendedValueInfo` need to @@ -141,6 +141,12 @@ struct LoweredValInfo val = nullptr; } + LoweredValInfo(IRType* t) + { + flavor = Flavor::Simple; + val = t; + } + static LoweredValInfo simple(IRInst* v) { LoweredValInfo info; @@ -212,7 +218,7 @@ struct BoundMemberInfo : ExtendedValueInfo DeclRef<Decl> declRef; // The type of this value - RefPtr<Type> type; + IRType* type; }; // Represents the result of a swizzle operation in @@ -224,7 +230,7 @@ struct BoundMemberInfo : ExtendedValueInfo struct SwizzledLValueInfo : ExtendedValueInfo { // The type of the expression. - RefPtr<Type> type; + IRType* type; // The base expression (this should be an l-value) LoweredValInfo base; @@ -272,12 +278,36 @@ LoweredValInfo LoweredValInfo::swizzledLValue( return info; } +// An "environment" for mapping AST declarations to IR values. +// +// This is required because in some cases we might lower the +// same AST declaration to the IR multiple times (e.g., when +// a generic transitively contains multiple functions, we +// will emit a distinct IR generic for each function, with +// its own copies of the generic parameters). +// +struct IRGenEnv +{ + // Map an AST-level declaration to the IR-level value that represents it. + Dictionary<Decl*, LoweredValInfo> mapDeclToValue; + + // The next outer env around this one + IRGenEnv* outer = nullptr; +}; + struct SharedIRGenContext { CompileRequest* compileRequest; ModuleDecl* mainModuleDecl; - Dictionary<Decl*, LoweredValInfo> declValues; + // The "global" environment for mapping declarations to their IR values. + IRGenEnv globalEnv; + + // Map an AST-level declaration of an interface + // requirement to the IR-level "key" that + // is used to fetch that requirement from a + // witness table. + Dictionary<Decl*, IRStructKey*> interfaceRequirementKeys; // Arrays we keep around strictly for memory-management purposes: @@ -297,8 +327,13 @@ struct SharedIRGenContext struct IRGenContext { + // Shared state for the IR generation process SharedIRGenContext* shared; + // environment for mapping AST decls to IR values + IRGenEnv* env; + + // IR builder to use when building code under this context IRBuilder* irBuilder; // The value to use for any `this` expressions @@ -310,12 +345,33 @@ struct IRGenContext // might be insufficient. LoweredValInfo thisVal; + explicit IRGenContext(SharedIRGenContext* inShared) + : shared(inShared) + , env(&inShared->globalEnv) + , irBuilder(nullptr) + {} + Session* getSession() { return shared->compileRequest->mSession; } }; +void setGlobalValue(SharedIRGenContext* sharedContext, Decl* decl, LoweredValInfo value) +{ + sharedContext->globalEnv.mapDeclToValue[decl] = value; +} + +void setGlobalValue(IRGenContext* context, Decl* decl, LoweredValInfo value) +{ + setGlobalValue(context->shared, decl, value); +} + +void setValue(IRGenContext* context, Decl* decl, LoweredValInfo value) +{ + context->env->mapDeclToValue[decl] = value; +} + // Ensure that a version of the given declaration has been emitted to the IR LoweredValInfo ensureDecl( IRGenContext* context, @@ -325,15 +381,8 @@ LoweredValInfo ensureDecl( // any needed specializations in place. LoweredValInfo emitDeclRef( IRGenContext* context, - DeclRef<Decl> declRef); - -// Emit necessary `specialize` instruction needed by a declRef. -// This is currently used by emitDeclRef() and emitFuncRef() -LoweredValInfo maybeEmitSpecializeInst(IRGenContext* context, - LoweredValInfo loweredDecl, // the lowered value of the inner decl - DeclRef<Decl> declRef // the full decl ref containing substitutions -); - + DeclRef<Decl> declRef, + IRType* type); IRInst* getSimpleVal(IRGenContext* context, LoweredValInfo lowered); @@ -402,23 +451,22 @@ IRInst* getOneValOfType( IRGenContext* context, IRType* type) { - if (auto basicType = dynamic_cast<BasicExpressionType*>(type)) + switch(type->op) { - switch (basicType->baseType) - { - case BaseType::Int: - case BaseType::UInt: - case BaseType::UInt64: - return context->irBuilder->getIntValue(type, 1); + case kIROp_IntType: + case kIROp_UIntType: + case kIROp_UInt64Type: + return context->irBuilder->getIntValue(type, 1); - case BaseType::Float: - case BaseType::Double: - return context->irBuilder->getFloatValue(type, 1.0); + case kIROp_HalfType: + case kIROp_FloatType: + case kIROp_DoubleType: + return context->irBuilder->getFloatValue(type, 1.0); - default: - break; - } + default: + break; } + // TODO: should make sure to handle vector and matrix types here SLANG_UNEXPECTED("inc/dec type"); @@ -473,103 +521,19 @@ LoweredValInfo emitPostOp( return LoweredValInfo::ptr(argPtr); } -IRInst* findWitnessTable( +LoweredValInfo lowerRValueExpr( IRGenContext* context, - DeclRef<Decl> declRef); - -LoweredValInfo emitWitnessTableRef( - IRGenContext* context, - Expr* expr) -{ - if (auto mbrExpr = dynamic_cast<MemberExpr*>(expr)) - { - if (auto typeConstraintDeclRef = mbrExpr->declRef.As<TypeConstraintDecl>()) - { - if (mbrExpr->declRef.getDecl()->ParentDecl->As<InterfaceDecl>() - || mbrExpr->declRef.getDecl()->ParentDecl->As<AssocTypeDecl>()) - { - RefPtr<Type> exprType = nullptr; - if (auto tt = mbrExpr->BaseExpression->type->As<TypeType>()) - exprType = tt->type; - else - exprType = mbrExpr->BaseExpression->type; - auto declRefType = exprType->GetCanonicalType()->AsDeclRefType(); - SLANG_ASSERT(declRefType); - IRInst* witnessTableVal = nullptr; - DeclRef<Decl> srcDeclRef = declRefType->declRef; - if (!declRefType->declRef.As<AssocTypeDecl>()) - { - // if we are referring to an actual type, don't include substitution - // and generate specialize instruction - srcDeclRef.substitutions = SubstitutionSet(); - } - witnessTableVal = context->irBuilder->emitFindWitnessTable(srcDeclRef, mbrExpr->declRef.As<TypeConstraintDecl>().getDecl()->getSup().type); - return maybeEmitSpecializeInst(context, LoweredValInfo::simple(witnessTableVal), declRefType->declRef); - } - } - if (auto inheritanceDecl = mbrExpr->declRef.As<InheritanceDecl>()) - { - if (mbrExpr->declRef.getDecl()->ParentDecl->As<AggTypeDeclBase>()) - { - return LoweredValInfo::simple(findWitnessTable(context, mbrExpr->declRef)); - } - } + Expr* expr); - if (auto genConstraintDeclRef = mbrExpr->declRef.As<GenericTypeConstraintDecl>()) - { - return LoweredValInfo::simple(context->irBuilder->getDeclRefVal(genConstraintDeclRef)); - } - } - SLANG_UNEXPECTED("unknown witness table expression"); -} +IRType* lowerType( + IRGenContext* context, + Type* type); -// Emit a reference to a function, where we have concluded -// that the original AST referenced `funcDeclRef`. The -// optional expression `funcExpr` can provide additional -// detail that might modify how we go about looking up -// the actual value to call. -LoweredValInfo emitFuncRef( +static IRType* lowerType( IRGenContext* context, - DeclRef<Decl> funcDeclRef, - Expr* funcExpr) + QualType const& type) { - if( !funcExpr ) - { - return emitDeclRef(context, funcDeclRef); - } - - // Let's look at the expression to see what additional - // information it gives us. - - if(auto funcMemberExpr = dynamic_cast<MemberExpr*>(funcExpr)) - { - auto baseExpr = funcMemberExpr->BaseExpression; - if(auto baseMemberExpr = baseExpr.As<MemberExpr>()) - { - auto baseMemberDeclRef = baseMemberExpr->declRef; - if(auto baseConstraintDeclRef = baseMemberDeclRef.As<TypeConstraintDecl>()) - { - // We are calling a method "through" a generic type - // parameter that was constrained to some type. - // That means `funcDeclRef` is a reference to the method - // on the `interface` type (which doesn't actually have - // a body, so we don't want to emit or call it), and - // we actually want to perform a lookup step to - // find the corresponding member on our chosen type. - RefPtr<Type> type = funcExpr->type; - auto loweredBaseWitnessTable = emitWitnessTableRef(context, baseMemberExpr); - auto loweredVal = LoweredValInfo::simple(context->irBuilder->emitLookupInterfaceMethodInst( - type, - loweredBaseWitnessTable.val, - funcDeclRef)); - return maybeEmitSpecializeInst(context, loweredVal, funcDeclRef); - } - } - } - - // We didn't trigger a special case, so just emit a reference - // to the function itself. - return emitDeclRef(context, funcDeclRef); + return lowerType(context, type.type); } // Given a `DeclRef` for something callable, along with a bunch of @@ -578,7 +542,7 @@ LoweredValInfo emitCallToDeclRef( IRGenContext* context, IRType* type, DeclRef<Decl> funcDeclRef, - Expr* funcExpr, + IRType* funcType, UInt argCount, IRInst* const* args) { @@ -587,7 +551,7 @@ LoweredValInfo emitCallToDeclRef( if (auto subscriptDeclRef = funcDeclRef.As<SubscriptDecl>()) { - // A reference to a subscript declaration is a special case, + // A reference to a subscript declaration is a special case, // because it is not possible to call a subscript directly; // we must call one of its accessors. // @@ -605,7 +569,7 @@ LoweredValInfo emitCallToDeclRef( { // The `ref` accessor will return a pointer to the value, so // we need to reflect that in the type of our `call` instruction. - RefPtr<Type> ptrType = context->getSession()->getPtrType(type); + IRType* ptrType = context->irBuilder->getPtrType(type); // Rather than call `emitCallToVal` here, we make a recursive call // to `emitCallToDeclRef` so that it can handle things like intrinsic-op @@ -614,7 +578,7 @@ LoweredValInfo emitCallToDeclRef( context, ptrType, refAccessorDeclRef, - funcExpr, + funcType, argCount, args); @@ -744,7 +708,16 @@ LoweredValInfo emitCallToDeclRef( } // Fallback case is to emit an actual call. - LoweredValInfo funcVal = emitFuncRef(context, funcDeclRef, funcExpr); + if(!funcType) + { + List<IRType*> argTypes; + for(UInt ii = 0; ii < argCount; ++ii) + { + argTypes.Add(args[ii]->getDataType()); + } + funcType = builder->getFuncType(argCount, argTypes.Buffer(), type); + } + LoweredValInfo funcVal = emitDeclRef(context, funcDeclRef, funcType); return emitCallToVal(context, type, funcVal, argCount, args); } @@ -752,15 +725,22 @@ LoweredValInfo emitCallToDeclRef( IRGenContext* context, IRType* type, DeclRef<Decl> funcDeclRef, - Expr* funcExpr, - List<IRInst*> const& args) + IRType* funcType, + List<IRInst*> const& args) +{ + return emitCallToDeclRef(context, type, funcDeclRef, funcType, args.Count(), args.Buffer()); +} + +IRInst* getFieldKey( + IRGenContext* context, + DeclRef<StructField> field) { - return emitCallToDeclRef(context, type, funcDeclRef, funcExpr, args.Count(), args.Buffer()); + return getSimpleVal(context, emitDeclRef(context, field, context->irBuilder->getKeyType())); } LoweredValInfo extractField( IRGenContext* context, - Type* fieldType, + IRType* fieldType, LoweredValInfo base, DeclRef<StructField> field) { @@ -775,7 +755,7 @@ LoweredValInfo extractField( builder->emitFieldExtract( fieldType, irBase, - builder->getDeclRefVal(field))); + getFieldKey(context, field))); } break; @@ -803,9 +783,9 @@ LoweredValInfo extractField( IRInst* irBasePtr = base.val; return LoweredValInfo::ptr( builder->emitFieldAddress( - context->getSession()->getPtrType(fieldType), + builder->getPtrType(fieldType), irBasePtr, - builder->getDeclRefVal(field))); + getFieldKey(context, field))); } break; } @@ -871,7 +851,7 @@ top: case LoweredValInfo::Flavor::SwizzledLValue: { auto swizzleInfo = lowered.getSwizzledLValueInfo(); - + return LoweredValInfo::simple(builder->emitSwizzle( swizzleInfo->type, getSimpleVal(context, swizzleInfo->base), @@ -911,45 +891,6 @@ IRInst* getSimpleVal(IRGenContext* context, LoweredValInfo lowered) } } -struct LoweredTypeInfo -{ - enum class Flavor - { - None, - Simple, - }; - - RefPtr<IRType> type; - Flavor flavor; - - LoweredTypeInfo() - { - flavor = Flavor::None; - } - - LoweredTypeInfo(IRType* t) - { - flavor = Flavor::Simple; - type = t; - } -}; - -RefPtr<Type> getSimpleType(LoweredTypeInfo lowered) -{ - switch(lowered.flavor) - { - case LoweredTypeInfo::Flavor::None: - return nullptr; - - case LoweredTypeInfo::Flavor::Simple: - return lowered.type; - - default: - SLANG_UNEXPECTED("unhandled value flavor"); - UNREACHABLE_RETURN(nullptr); - } -} - LoweredValInfo lowerVal( IRGenContext* context, Val* val); @@ -962,42 +903,10 @@ IRInst* lowerSimpleVal( return getSimpleVal(context, lowered); } -LoweredTypeInfo lowerType( - IRGenContext* context, - Type* type); - -static LoweredTypeInfo lowerType( - IRGenContext* context, - QualType const& type) -{ - return lowerType(context, type.type); -} - -// Lower a type and expect the result to be simple -RefPtr<Type> lowerSimpleType( - IRGenContext* context, - Type* type) -{ - auto lowered = lowerType(context, type); - return getSimpleType(lowered); -} - -RefPtr<Type> lowerSimpleType( - IRGenContext* context, - QualType const& type) -{ - auto lowered = lowerType(context, type); - return getSimpleType(lowered); -} - LoweredValInfo lowerLValueExpr( IRGenContext* context, Expr* expr); -LoweredValInfo lowerRValueExpr( - IRGenContext* context, - Expr* expr); - void assign( IRGenContext* context, LoweredValInfo const& left, @@ -1014,29 +923,41 @@ LoweredValInfo lowerDecl( IRType* getIntType( IRGenContext* context) { - return context->getSession()->getBuiltinType(BaseType::Int); + return context->irBuilder->getBasicType(BaseType::Int); } -RefPtr<IRFuncType> getFuncType( - IRGenContext* context, - UInt paramCount, - RefPtr<IRType> const* paramTypes, - IRType* resultType) +IRStructKey* getInterfaceRequirementKey( + IRGenContext* context, + Decl* requirementDecl) { - RefPtr<FuncType> funcType = new FuncType(); - funcType->setSession(context->getSession()); - funcType->resultType = resultType; - for (UInt pp = 0; pp < paramCount; ++pp) + IRStructKey* requirementKey = nullptr; + if(context->shared->interfaceRequirementKeys.TryGetValue(requirementDecl, requirementKey)) { - funcType->paramTypes.Add(paramTypes[pp]); + return requirementKey; } - return funcType; + + IRBuilder builderStorage = *context->irBuilder; + auto builder = &builderStorage; + + builder->setInsertInto(builder->sharedBuilder->module->getModuleInst()); + + // Construct a key to serve as the representation of + // this requirement in the IR, and to allow lookup + // into the declaration. + requirementKey = builder->createStructKey(); + requirementKey->mangledName = context->getSession()->getNameObj( + getMangledName(requirementDecl)); + + context->shared->interfaceRequirementKeys.Add(requirementDecl, requirementKey); + + return requirementKey; } + SubstitutionSet lowerSubstitutions(IRGenContext* context, SubstitutionSet subst); // -struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, LoweredTypeInfo> +struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, LoweredValInfo> { IRGenContext* context; @@ -1047,6 +968,42 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower SLANG_UNIMPLEMENTED_X("value lowering"); } + LoweredValInfo visitGenericParamIntVal(GenericParamIntVal* val) + { + return emitDeclRef(context, val->declRef, + lowerType(context, GetType(val->declRef))); + } + + LoweredValInfo visitDeclaredSubtypeWitness(DeclaredSubtypeWitness* val) + { + return emitDeclRef(context, val->declRef, + context->irBuilder->getWitnessTableType()); + } + + LoweredValInfo visitTransitiveSubtypeWitness( + TransitiveSubtypeWitness* val) + { + // The base (subToMid) will turn into a value with + // witness-table type. + IRInst* baseWitnessTable = lowerSimpleVal(context, val->subToMid); + + // The next step should map to an interface requirement + // that is itself an interface conformance, so the result + // of lowering this value should be a "key" that we can + // use to look up a witness table. + IRInst* requirementKey = getInterfaceRequirementKey(context, val->midToSup.getDecl()); + + // TODO: There are some ugly cases here if `midToSup` is allowed + // to be an arbitrary witness, rather than just a declared one, + // and we should probably change the front-end representation + // to reflect the right constraints. + + return LoweredValInfo::simple(getBuilder()->emitLookupInterfaceMethodInst( + nullptr, + baseWitnessTable, + requirementKey)); + } + LoweredValInfo visitConstantIntVal(ConstantIntVal* val) { // TODO: it is a bit messy here that the `ConstantIntVal` representation @@ -1056,70 +1013,135 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower return LoweredValInfo::simple(getBuilder()->getIntValue(type, val->value)); } - LoweredTypeInfo visitType(Type* type) + IRFuncType* visitFuncType(FuncType* type) { - // TODO(tfoley): Now that we use the AST types directly in the IR, there - // isn't much to do in the "lowering" step. Still, there might be cases - // where certain kinds of legalization need to take place, so this - // visitor setup might still be needed in the long run. - return LoweredTypeInfo(type); -// SLANG_UNIMPLEMENTED_X("type lowering"); + IRType* resultType = lowerType(context, type->getResultType()); + UInt paramCount = type->getParamCount(); + List<IRType*> paramTypes; + for (UInt pp = 0; pp < paramCount; ++pp) + { + paramTypes.Add(lowerType(context, type->getParamType(pp))); + } + return getBuilder()->getFuncType( + paramCount, + paramTypes.Buffer(), + resultType); } - LoweredTypeInfo visitFuncType(FuncType* type) + IRType* visitDeclRefType(DeclRefType* type) { - return LoweredTypeInfo(type); + return (IRType*) getSimpleVal( + context, + emitDeclRef(context, type->declRef, + context->irBuilder->getTypeKind())); } - void addGenericArgs(List<IRInst*>* ioArgs, DeclRefBase declRef) + IRType* visitNamedExpressionType(NamedExpressionType* type) { - auto subs = declRef.substitutions.genericSubstitutions; - while(subs) - { - for (auto aa : subs->args) - { - (*ioArgs).Add(getSimpleVal(context, lowerVal(context, aa))); - } - subs = subs->outer; - } + return (IRType*) getSimpleVal(context, + emitDeclRef(context, type->declRef, + context->irBuilder->getTypeKind())); } - LoweredTypeInfo visitDeclRefType(DeclRefType* type) + IRType* visitBasicExpressionType(BasicExpressionType* type) { - // If the type in question comes from the module we are - // trying to lower, then we need to make sure to - // emit everything relevant to its declaration. + return getBuilder()->getBasicType( + type->baseType); + } - // TODO: actually test what module the type is coming from. + IRType* visitVectorExpressionType(VectorExpressionType* type) + { + auto elementType = lowerType(context, type->elementType); + auto elementCount = lowerSimpleVal(context, type->elementCount); - lowerDecl(context, type->declRef); - return LoweredTypeInfo(type); + return getBuilder()->getVectorType( + elementType, + elementCount); } - LoweredTypeInfo visitBasicExpressionType(BasicExpressionType* type) + IRType* visitMatrixExpressionType(MatrixExpressionType* type) { - return LoweredTypeInfo(type); + auto elementType = lowerType(context, type->getElementType()); + auto rowCount = lowerSimpleVal(context, type->getRowCount()); + auto columnCount = lowerSimpleVal(context, type->getColumnCount()); + + return getBuilder()->getMatrixType( + elementType, + rowCount, + columnCount); } - LoweredTypeInfo visitVectorExpressionType(VectorExpressionType* type) + IRType* visitArrayExpressionType(ArrayExpressionType* type) { - return LoweredTypeInfo(type); + auto elementType = lowerType(context, type->baseType); + if (type->ArrayLength) + { + auto elementCount = lowerSimpleVal(context, type->ArrayLength); + return getBuilder()->getArrayType( + elementType, + elementCount); + } + else + { + return getBuilder()->getUnsizedArrayType( + elementType); + } + } + + // Lower a type where the type declaration being referenced is assumed + // to be an intrinsic type, which can thus be lowered to a simple IR + // type with the appropriate opcode. + IRType* lowerSimpleIntrinsicType(DeclRefType* type) + { + auto intrinsicTypeModifier = type->declRef.getDecl()->FindModifier<IntrinsicTypeModifier>(); + SLANG_ASSERT(intrinsicTypeModifier); + IROp op = IROp(intrinsicTypeModifier->irOp); + return getBuilder()->getType(op); + } + + // Lower a type where the type declaration being referenced is assumed + // to be an intrinsic type with a single generic type parameter, and + // which can thus be lowered to a simple IR type with the appropriate opcode. + IRType* lowerGenericIntrinsicType(DeclRefType* type, Type* elementType) + { + auto intrinsicTypeModifier = type->declRef.getDecl()->FindModifier<IntrinsicTypeModifier>(); + SLANG_ASSERT(intrinsicTypeModifier); + IROp op = IROp(intrinsicTypeModifier->irOp); + IRInst* irElementType = lowerType(context, elementType); + return getBuilder()->getType( + op, + 1, + &irElementType); } - LoweredTypeInfo visitMatrixExpressionType(MatrixExpressionType* type) + IRType* visitResourceType(ResourceType* type) { - return LoweredTypeInfo(type); + return lowerGenericIntrinsicType(type, type->elementType); } - LoweredTypeInfo visitArrayExpressionType(ArrayExpressionType* type) + IRType* visitSamplerStateType(SamplerStateType* type) { - return LoweredTypeInfo(type); + return lowerSimpleIntrinsicType(type); } - LoweredTypeInfo visitIRBasicBlockType(IRBasicBlockType* type) + IRType* visitBuiltinGenericType(BuiltinGenericType* type) { - return LoweredTypeInfo(type); + return lowerGenericIntrinsicType(type, type->elementType); } + + IRType* visitUntypedBufferResourceType(UntypedBufferResourceType* type) + { + return lowerSimpleIntrinsicType(type); + } + + // 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); } + UNEXPECTED_CASE(GenericDeclRefType) + UNEXPECTED_CASE(TypeType) + UNEXPECTED_CASE(ErrorType) + UNEXPECTED_CASE(InitializerListType) + UNEXPECTED_CASE(OverloadGroupType) }; LoweredValInfo lowerVal( @@ -1131,18 +1153,51 @@ LoweredValInfo lowerVal( return visitor.dispatch(val); } -LoweredTypeInfo lowerType( +IRType* lowerType( IRGenContext* context, Type* type) { ValLoweringVisitor visitor; visitor.context = context; - return visitor.dispatchType(type); + return (IRType*) getSimpleVal(context, visitor.dispatchType(type)); +} + +void addVarDecorations( + IRGenContext* context, + IRInst* inst, + Decl* decl) +{ + auto builder = context->irBuilder; + for(RefPtr<Modifier> mod : decl->modifiers) + { + if(mod.As<HLSLNoInterpolationModifier>()) + { + builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::NoInterpolation; + } + else if(mod.As<HLSLNoPerspectiveModifier>()) + { + builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::NoPerspective; + } + else if(mod.As<HLSLLinearModifier>()) + { + builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Linear; + } + else if(mod.As<HLSLSampleModifier>()) + { + builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Sample; + } + else if(mod.As<HLSLCentroidModifier>()) + { + builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Centroid; + } + + // TODO: what are other modifiers we need to propagate through? + } } LoweredValInfo createVar( IRGenContext* context, - RefPtr<Type> type, + IRType* type, Decl* decl = nullptr) { auto builder = context->irBuilder; @@ -1150,6 +1205,8 @@ LoweredValInfo createVar( if (decl) { + addVarDecorations(context, irAlloc, decl); + builder->addHighLevelDeclDecoration(irAlloc, decl); } @@ -1198,7 +1255,10 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> LoweredValInfo visitVarExpr(VarExpr* expr) { - LoweredValInfo info = emitDeclRef(context, expr->declRef); + LoweredValInfo info = emitDeclRef( + context, + expr->declRef, + lowerType(context, expr->type)); return info; } @@ -1263,7 +1323,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // as an l-value, since that is the easiest way to handle it. LoweredValInfo visitDerefExpr(DerefExpr* expr) { - auto loweredType = lowerType(context, expr->type); auto loweredBase = lowerRValueExpr(context, expr->base); // TODO: handle tupel-type for `base` @@ -1273,10 +1332,10 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // need to extract the value type from that pointer here. // IRInst* loweredBaseVal = getSimpleVal(context, loweredBase); - RefPtr<Type> loweredBaseType = loweredBaseVal->getDataType(); + IRType* loweredBaseType = loweredBaseVal->getDataType(); - if (loweredBaseType->As<PointerLikeType>() - || loweredBaseType->As<PtrTypeBase>()) + if (as<IRPointerLikeType>(loweredBaseType) + || as<IRPtrTypeBase>(loweredBaseType)) { // Note that we do *not* perform an actual `load` operation // here, but rather just use the pointer value to construct @@ -1305,7 +1364,8 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> LoweredValInfo visitInitializerListExpr(InitializerListExpr* expr) { // Allocate a temporary of the given type - RefPtr<Type> type = lowerSimpleType(context, expr->type); + auto type = expr->type; + IRType* irType = lowerType(context, type); List<IRInst*> args; UInt argCount = expr->args.Count(); @@ -1315,7 +1375,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> if (auto arrayType = type->As<ArrayExpressionType>()) { UInt elementCount = (UInt) GetIntVal(arrayType->ArrayLength); - auto elementType = lowerType(context, arrayType->baseType); for (UInt ee = 0; ee < elementCount; ++ee) { @@ -1332,12 +1391,10 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } return LoweredValInfo::simple( - getBuilder()->emitMakeArray(type, args.Count(), args.Buffer())); + getBuilder()->emitMakeArray(irType, args.Count(), args.Buffer())); } else if (auto vectorType = type->As<VectorExpressionType>()) { - auto elementType = lowerType(context, vectorType->elementType); - UInt elementCount = (UInt) GetIntVal(vectorType->elementCount); UInt argCounter = 0; @@ -1357,7 +1414,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } return LoweredValInfo::simple( - getBuilder()->emitMakeVector(type, args.Count(), args.Buffer())); + getBuilder()->emitMakeVector(irType, args.Count(), args.Buffer())); } else if (auto declRefType = type->As<DeclRefType>()) { @@ -1384,7 +1441,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } return LoweredValInfo::simple( - getBuilder()->emitMakeStruct(type, args.Count(), args.Buffer())); + getBuilder()->emitMakeStruct(irType, args.Count(), args.Buffer())); } else { @@ -1406,13 +1463,13 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> LoweredValInfo visitIntegerLiteralExpr(IntegerLiteralExpr* expr) { - auto type = lowerSimpleType(context, expr->type); + auto type = lowerType(context, expr->type); return LoweredValInfo::simple(context->irBuilder->getIntValue(type, expr->value)); } LoweredValInfo visitFloatingPointLiteralExpr(FloatingPointLiteralExpr* expr) { - auto type = lowerSimpleType(context, expr->type); + auto type = lowerType(context, expr->type); return LoweredValInfo::simple(context->irBuilder->getFloatValue(type, expr->value)); } @@ -1450,7 +1507,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> for (auto paramDeclRef : getMembersOfType<ParamDecl>(funcDeclRef)) { auto paramDecl = paramDeclRef.getDecl(); - RefPtr<Type> paramType = lowerSimpleType(context, GetType(paramDeclRef)); + IRType* paramType = lowerType(context, GetType(paramDeclRef)); UInt argIndex = argCounter++; RefPtr<Expr> argExpr; @@ -1656,7 +1713,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> LoweredValInfo visitInvokeExpr(InvokeExpr* expr) { - auto type = lowerSimpleType(context, expr->type); + auto type = lowerType(context, expr->type); // We are going to look at the syntactic form of // the "function" expression, so that we can avoid @@ -1704,12 +1761,13 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // These may include `out` and `inout` arguments that // require "fixup" work on the other side. // + auto funcType = lowerType(context, funcExpr->type); addDirectCallArgs(expr, funcDeclRef, &irArgs, &argFixups); auto result = emitCallToDeclRef( context, type, funcDeclRef, - funcExpr, + funcType, irArgs); applyOutArgumentFixups(argFixups); return result; @@ -1733,9 +1791,9 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } LoweredValInfo subscriptValue( - LoweredTypeInfo type, + IRType* type, LoweredValInfo baseVal, - IRInst* indexVal) + IRInst* indexVal) { auto builder = getBuilder(); switch (baseVal.flavor) @@ -1743,14 +1801,14 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> case LoweredValInfo::Flavor::Simple: return LoweredValInfo::simple( builder->emitElementExtract( - getSimpleType(type), + type, getSimpleVal(context, baseVal), indexVal)); case LoweredValInfo::Flavor::Ptr: return LoweredValInfo::ptr( builder->emitElementAddress( - context->getSession()->getPtrType(getSimpleType(type)), + context->irBuilder->getPtrType(type), baseVal.val, indexVal)); @@ -1762,16 +1820,17 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } LoweredValInfo extractField( - LoweredTypeInfo fieldType, + IRType* fieldType, LoweredValInfo base, DeclRef<StructField> field) { - return Slang::extractField(context, getSimpleType(fieldType), base, field); + return Slang::extractField(context, fieldType, base, field); } LoweredValInfo visitStaticMemberExpr(StaticMemberExpr* expr) { - return emitDeclRef(context, expr->declRef); + return emitDeclRef(context, expr->declRef, + lowerType(context, expr->type)); } LoweredValInfo visitGenericAppExpr(GenericAppExpr* /*expr*/) @@ -1809,7 +1868,7 @@ struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVis // we need to construct a "sizzled l-value." LoweredValInfo visitSwizzleExpr(SwizzleExpr* expr) { - auto irType = lowerSimpleType(context, expr->type); + auto irType = lowerType(context, expr->type); auto loweredBase = lowerRValueExpr(context, expr->base); RefPtr<SwizzledLValueInfo> swizzledLValue = new SwizzledLValueInfo(); @@ -1835,7 +1894,7 @@ struct RValueExprLoweringVisitor : ExprLoweringVisitorBase<RValueExprLoweringVis // emitting the swizzle instuctions directly. LoweredValInfo visitSwizzleExpr(SwizzleExpr* expr) { - auto irType = lowerSimpleType(context, expr->type); + auto irType = lowerType(context, expr->type); auto irBase = getSimpleVal(context, lowerRValueExpr(context, expr->base)); auto builder = getBuilder(); @@ -1923,7 +1982,17 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> return; auto varDecl = stmt->varDecl; - auto varType = varDecl->type; + auto varType = lowerType(context, varDecl->type); + + IRGenEnv subEnvStorage; + IRGenEnv* subEnv = &subEnvStorage; + subEnv->outer = context->env; + + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->env = subEnv; + + for (IntegerLiteralValue ii = rangeBeginVal; ii < rangeEndVal; ++ii) { @@ -1931,9 +2000,9 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> varType, ii); - context->shared->declValues[varDecl] = LoweredValInfo::simple(constVal); + subEnv->mapDeclToValue[varDecl] = LoweredValInfo::simple(constVal); - lowerStmt(context, stmt->body); + lowerStmt(subContext, stmt->body); } } @@ -2666,7 +2735,6 @@ top: // try to handle everything uniformly. // auto swizzleInfo = left.getSwizzledLValueInfo(); - auto type = swizzleInfo->type; auto loweredBase = swizzleInfo->base; // Load from the base value: @@ -2700,19 +2768,18 @@ top: // When storing to such a value, we need to emit a call // to the appropriate builtin "setter" accessor. auto subscriptInfo = left.getBoundSubscriptInfo(); - auto type = subscriptInfo->type; // Search for an appropriate "setter" declaration auto setters = getMembersOfType<SetterDecl>(subscriptInfo->declRef); if (setters.Count()) { auto allArgs = subscriptInfo->args; - + addArgs(context, &allArgs, right); emitCallToDeclRef( context, - context->getSession()->getVoidType(), + builder->getVoidType(), *setters.begin(), nullptr, allArgs); @@ -2780,11 +2847,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> LoweredValInfo visitDeclBase(DeclBase* /*decl*/) { SLANG_UNIMPLEMENTED_X("decl catch-all"); + UNREACHABLE_RETURN(LoweredValInfo()); } LoweredValInfo visitDecl(Decl* /*decl*/) { SLANG_UNIMPLEMENTED_X("decl catch-all"); + UNREACHABLE_RETURN(LoweredValInfo()); } LoweredValInfo visitExtensionDecl(ExtensionDecl* decl) @@ -2814,9 +2883,33 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return LoweredValInfo(); } - LoweredValInfo visitTypeDefDecl(TypeDefDecl * decl) + LoweredValInfo visitTypeDefDecl(TypeDefDecl* decl) { - return LoweredValInfo::simple(context->irBuilder->getTypeVal(decl->type.type)); + // A type alias declaration may be generic, if it is + // nested under a generic type/function/etc. + // + IRBuilder subBuilderStorage = *getBuilder(); + IRBuilder* subBuilder = &subBuilderStorage; + IRGeneric* outerGeneric = emitOuterGenerics(subBuilder, decl, decl); + + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->irBuilder = subBuilder; + + // TODO: if a type alias declaration can have linkage, + // we will need to lower it to some kind of global + // value in the IR so that we can attach a name to it. + // + // For now, we can only attach a name *if* the type + // alias is somehow generic. + if(outerGeneric) + { + setMangledName(outerGeneric, getMangledName(decl)); + } + + auto type = lowerType(subContext, decl->type.type); + + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, type)); } LoweredValInfo visitGenericTypeParamDecl(GenericTypeParamDecl* /*decl*/) @@ -2824,118 +2917,219 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return LoweredValInfo(); } - void walkInheritanceHierarchyAndCreateWitnessTableCopies(IRWitnessTable* witnessTable, Type* subType, InheritanceDecl* inheritanceDecl) + LoweredValInfo visitGenericTypeConstraintDecl(GenericTypeConstraintDecl* decl) { - auto baseDeclRef = inheritanceDecl->base.type.As<DeclRefType>(); - if (auto baseInterfaceDeclRef = baseDeclRef->declRef.As<InterfaceDecl>()) + // This might be a type constraint on an associated type, + // in which case it should lower as the key for that + // interface requirement. + if(auto assocTypeDecl = decl->ParentDecl->As<AssocTypeDecl>()) { - for (auto subInheritanceDeclRef : getMembersOfType<InheritanceDecl>(baseInterfaceDeclRef)) + // TODO: might need extra steps if we ever allow + // generic associated types. + + + if(auto interfaceDecl = assocTypeDecl->ParentDecl->As<InterfaceDecl>()) { - auto cpyMangledName = context->getSession()->getNameObj(getMangledNameForConformanceWitness(subType, subInheritanceDeclRef.getDecl()->getSup().type)); - if (!witnessTablesDictionary.ContainsKey(cpyMangledName)) + // Okay, this seems to be an interface rquirement, and + // we should lower it as such. + return LoweredValInfo::simple(getInterfaceRequirementKey(decl)); + } + } + + if(auto globalGenericParamDecl = decl->ParentDecl->As<GlobalGenericParamDecl>()) + { + // This is a constraint on a global generic type parameters, + // and so it should lower as a parameter of its own. + + auto inst = getBuilder()->emitGlobalGenericParam(); + setMangledName(inst, getMangledName(decl)); + return LoweredValInfo::simple(inst); + } + + // Otherwise we really don't expect to see a type constraint + // declaration like this during lowering, because a generic + // should have set up a parameter for any constraints as + // part of being lowered. + + SLANG_UNEXPECTED("generic type constraint during lowering"); + UNREACHABLE_RETURN(LoweredValInfo()); + } + + LoweredValInfo visitGlobalGenericParamDecl(GlobalGenericParamDecl* decl) + { + auto inst = getBuilder()->emitGlobalGenericParam(); + setMangledName(inst, getMangledName(decl)); + return LoweredValInfo::simple(inst); + } + + void lowerWitnessTable( + IRGenContext* subContext, + WitnessTable* astWitnessTable, + IRWitnessTable* irWitnessTable, + Dictionary<WitnessTable*, IRWitnessTable*> mapASTToIRWitnessTable) + { + auto subBuilder = subContext->irBuilder; + + for(auto entry : astWitnessTable->requirementDictionary) + { + auto requiredMemberDecl = entry.Key; + auto satisfyingWitness = entry.Value; + + auto irRequirementKey = getInterfaceRequirementKey(requiredMemberDecl); + IRInst* irSatisfyingVal = nullptr; + + switch(satisfyingWitness.getFlavor()) + { + case RequirementWitness::Flavor::declRef: { - auto cpyTable = context->irBuilder->createWitnessTable(); - cpyTable->mangledName = cpyMangledName; - context->irBuilder->createWitnessTableEntry(witnessTable, - context->irBuilder->getDeclRefVal(subInheritanceDeclRef), cpyTable); + auto satisfyingDeclRef = satisfyingWitness.getDeclRef(); + irSatisfyingVal = getSimpleVal(subContext, + emitDeclRef(subContext, satisfyingDeclRef, + // TODO: we need to know what type to plug in here... + nullptr)); + } + break; - // We need to copy all the entries from the original table to this new table. - for (auto entry : witnessTable->getEntries()) + case RequirementWitness::Flavor::val: + { + auto satisfyingVal = satisfyingWitness.getVal(); + irSatisfyingVal = lowerSimpleVal(subContext, satisfyingVal); + } + break; + + case RequirementWitness::Flavor::witnessTable: + { + auto astReqWitnessTable = satisfyingWitness.getWitnessTable(); + IRWitnessTable* irSatisfyingWitnessTable = nullptr; + if(!mapASTToIRWitnessTable.TryGetValue(astReqWitnessTable, irSatisfyingWitnessTable)) { - context->irBuilder->createWitnessTableEntry(cpyTable, - entry->requirementKey.get(), - entry->satisfyingVal.get()); - } + // Need to construct a sub-witness-table + irSatisfyingWitnessTable = subBuilder->createWitnessTable(); - witnessTablesDictionary.Add(cpyTable->mangledName, cpyTable); - walkInheritanceHierarchyAndCreateWitnessTableCopies(witnessTable, subType, subInheritanceDeclRef.getDecl()); + // Recursively lower the sub-table. + lowerWitnessTable( + subContext, + astReqWitnessTable, + irSatisfyingWitnessTable, + mapASTToIRWitnessTable); + + irSatisfyingWitnessTable->moveToEnd(); + } + irSatisfyingVal = irSatisfyingWitnessTable; } + break; + + default: + SLANG_UNEXPECTED("handled requirement witness case"); + break; } + + + subBuilder->createWitnessTableEntry( + irWitnessTable, + irRequirementKey, + irSatisfyingVal); } } - Dictionary<Name*, IRWitnessTable*> witnessTablesDictionary; - LoweredValInfo visitInheritanceDecl(InheritanceDecl* inheritanceDecl) { - // Construct a type for the parent declaration. + // An inheritance clause inside of an `interface` + // declaration should not give rise to a witness + // table, because it represents something the + // interface requires, and not what it provides. // - // TODO: if this inheritance declaration is under an extension, - // then we should construct the type that is being extended, - // and not a reference to the extension itself. - auto parentDecl = inheritanceDecl->ParentDecl; - RefPtr<Type> type; - if (auto extParentDecl = dynamic_cast<ExtensionDecl*>(parentDecl)) + if (auto parentInterfaceDecl = parentDecl->As<InterfaceDecl>()) + { + return LoweredValInfo::simple(getInterfaceRequirementKey(inheritanceDecl)); + } + // + // We also need to cover the case where an `extension` + // declaration is being used to add a conformance to + // an existing `interface`: + // + if(auto parentExtensionDecl = parentDecl->As<ExtensionDecl>()) { - type = extParentDecl->targetType.type; - if (auto declRefType = type.As<DeclRefType>()) + auto targetType = parentExtensionDecl->targetType; + if(auto targetDeclRefType = targetType->As<DeclRefType>()) { - if (auto aggTypeDecl = declRefType->declRef.As<AggTypeDecl>()) - parentDecl = aggTypeDecl.getDecl(); + if(auto targetInterfaceDeclRef = targetDeclRefType->declRef.As<InterfaceDecl>()) + { + return LoweredValInfo::simple(getInterfaceRequirementKey(inheritanceDecl)); + } } } + + // Find the type that is doing the inheriting. + // Under normal circumstances it is the type declaration that + // is the parent for the inheritance declaration, but if + // the inheritance declaration is on an `extension` declaration, + // then we need to identify the type being extended. + // + RefPtr<Type> subType; + if (auto extParentDecl = dynamic_cast<ExtensionDecl*>(parentDecl)) + { + subType = extParentDecl->targetType.type; + } else { - type = DeclRefType::Create( + subType = DeclRefType::Create( context->getSession(), makeDeclRef(parentDecl)); } + // What is the super-type that we have declared we inherit from? RefPtr<Type> superType = inheritanceDecl->base.type; // Construct the mangled name for the witness table, which depends // on the type that is conforming, and the type that it conforms to. - auto mangledName = context->getSession()->getNameObj(getMangledNameForConformanceWitness(type, superType)); - - // Build an IR level witness table, which will represent the - // conformance of the type to its super-type. - auto witnessTable = context->irBuilder->createWitnessTable(); - witnessTable->mangledName = mangledName; - - witnessTablesDictionary.Add(mangledName, witnessTable); - - if (parentDecl->ParentDecl) - witnessTable->genericDecl = dynamic_cast<GenericDecl*>(parentDecl->ParentDecl); - witnessTable->subTypeDeclRef = makeDeclRef(parentDecl); - witnessTable->subTypeDeclRef.substitutions = createDefaultSubstitutions(context->getSession(), parentDecl); - witnessTable->supTypeDeclRef = inheritanceDecl->base.type->AsDeclRefType()->declRef; - - // Register the value now, rather than later, to avoid - // infinite recursion. - context->shared->declValues[inheritanceDecl] = LoweredValInfo::simple(witnessTable); - - - // Semantic checking will have filled in a dictionary of - // witnesses for requirements in the interface, and we - // will now navigate that dictionary to fill in the witness table. - for (auto entry : inheritanceDecl->requirementWitnesses) - { - auto requiredMemberDeclRef = entry.Key; - auto satisfyingMemberDeclRef = entry.Value; - - auto irRequirement = context->irBuilder->getDeclRefVal(requiredMemberDeclRef); - IRInst* irSatisfyingVal = nullptr; - if (satisfyingMemberDeclRef.As<GenericTypeConstraintDecl>()) - irSatisfyingVal = context->irBuilder->getDeclRefVal(satisfyingMemberDeclRef); - else - irSatisfyingVal = getSimpleVal(context, ensureDecl(context, satisfyingMemberDeclRef)); + // + // TODO: This approach doesn't really make sense for generic `extension` conformances. + auto mangledName = context->getSession()->getNameObj( + getMangledNameForConformanceWitness(subType, superType)); - context->irBuilder->createWitnessTableEntry( - witnessTable, - irRequirement, - irSatisfyingVal); - } + // A witness table may need to be generic, if the outer + // declaration (either a type declaration or an `extension`) + // is generic. + // + IRBuilder subBuilderStorage = *getBuilder(); + IRBuilder* subBuilder = &subBuilderStorage; + emitOuterGenerics(subBuilder, inheritanceDecl, inheritanceDecl); - witnessTable->moveToEnd(); - walkInheritanceHierarchyAndCreateWitnessTableCopies(witnessTable, type, inheritanceDecl); + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->irBuilder = subBuilder; - // A direct reference to this inheritance relationship (e.g., - // as a subtype witness) will take the form of a reference to - // the witness table in the IR. - return LoweredValInfo::simple(witnessTable); - } + // Lower the super-type to force its declaration to be lowered. + // + // Note: we are using the "sub-context" here because the + // type being inherited from could reference generic parameters, + // and we need those parameters to lower as references to + // the parameters of our IR-level generic. + // + lowerType(subContext, superType); + + // Create the IR-level witness table + auto irWitnessTable = subBuilder->createWitnessTable(); + setMangledName(irWitnessTable, mangledName); + + // Register the value now, rather than later, to avoid any possible infinite recursion. + setGlobalValue(context, inheritanceDecl, LoweredValInfo::simple(irWitnessTable)); + // Make sure that all the entries in the witness table have been filled in, + // including any cases where there are sub-witness-tables for conformances + Dictionary<WitnessTable*, IRWitnessTable*> mapASTToIRWitnessTable; + lowerWitnessTable( + subContext, + inheritanceDecl->witnessTable, + irWitnessTable, + mapASTToIRWitnessTable); + + irWitnessTable->moveToEnd(); + + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irWitnessTable)); + } LoweredValInfo visitDeclGroup(DeclGroup* declGroup) { @@ -2996,19 +3190,23 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> LoweredValInfo lowerGlobalVarDecl(VarDeclBase* decl) { - RefPtr<Type> varType = lowerSimpleType(context, decl->getType()); + IRType* varType = lowerType(context, decl->getType()); if (decl->HasModifier<HLSLGroupSharedModifier>()) { - varType = context->getSession()->getGroupSharedType(varType); + // TODO: here we are applying the rate qualifier to + // the *data type* of the variable, when we really + // should be applying the rate to the variable itself. + // + // This ends up making a distinction between + // `Ptr<@GroupShared X>` and `@GroupShared Ptr<X>`. + // The latter is more technically correct, but the + // code generation logic currently looks for the former. + + varType = getBuilder()->getRateQualifiedType( + getBuilder()->getGroupSharedRate(), + varType); } - // TODO: There might be other cases of storage qualifiers - // that should translate into "rate-qualified" types - // for the variable's storage. - // - // TODO: Also worth asking whether we should have semantic - // checking be responsible for applying qualifiers applied - // to a variable over to its type, when it makes sense. auto builder = getBuilder(); @@ -3035,8 +3233,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // A global variable's SSA value is a *pointer* to // the underlying storage. - context->shared->declValues[ - DeclRef<VarDeclBase>(decl, nullptr)] = globalVal; + setGlobalValue(context, decl, globalVal); if (isImportedDecl(decl)) { @@ -3064,12 +3261,15 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> subContext->irBuilder->emitReturn(getSimpleVal(subContext, initVal)); } + irGlobal->moveToEnd(); + return globalVal; } LoweredValInfo visitGenericValueParamDecl(GenericValueParamDecl* decl) { - return LoweredValInfo::simple(context->irBuilder->getDeclRefVal(DeclRefBase(decl))); + return emitDeclRef(context, makeDeclRef(decl), + lowerType(context, decl->type)); } LoweredValInfo visitVarDeclBase(VarDeclBase* decl) @@ -3092,7 +3292,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // emit an SSA value in this common case. // - RefPtr<Type> varType = lowerSimpleType(context, decl->getType()); + IRType* varType = lowerType(context, decl->getType()); // TODO: If the variable is marked `static` then we need to // deal with it specially: we should move its allocation out @@ -3125,7 +3325,9 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> { // TODO: This logic is duplicated with the global-variable // case. We should seek to share it. - varType = context->getSession()->getGroupSharedType(varType); + varType = getBuilder()->getRateQualifiedType( + getBuilder()->getGroupSharedRate(), + varType); } LoweredValInfo varVal = createVar(context, varType, decl); @@ -3137,14 +3339,97 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> assign(context, varVal, initVal); } - context->shared->declValues[ - DeclRef<VarDeclBase>(decl, nullptr)] = varVal; + setGlobalValue(context, decl, varVal); return varVal; } + IRStructKey* getInterfaceRequirementKey(Decl* requirementDecl) + { + return Slang::getInterfaceRequirementKey(context, requirementDecl); + } + + 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 + // be used for lookup operations into witness + // tables that promise conformance to the interface. + // + // TODO: we don't handle the case here of an interface + // with concrete/default implementations for any + // of its members. + // + // TODO: If we want to support using an interface as + // an existential type, then we might need to emit + // a witness table for the interface type's conformance + // to its own interface. + // + for (auto requirementDecl : decl->Members) + { + getInterfaceRequirementKey(requirementDecl); + + // 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 = requirementDecl.As<AssocTypeDecl>()) + { + for (auto constraintDecl : associatedTypeDecl->getMembersOfType<TypeConstraintDecl>()) + { + getInterfaceRequirementKey(constraintDecl); + } + } + } + + return LoweredValInfo(); + } + + IRGeneric* getOuterGeneric(IRGlobalValue* gv) + { + auto parentBlock = as<IRBlock>(gv->getParent()); + if (!parentBlock) return nullptr; + + auto parentGeneric = as<IRGeneric>(parentBlock->getParent()); + return parentGeneric; + } + + void setMangledName(IRGlobalValue* inst, Name* name) + { + // If the instruction is nested inside one or more generics, + // then the mangled name should really apply to the outer-most + // generic, and not the declaration nested inside. + + IRGlobalValue* gv = inst; + while (auto outerGeneric = getOuterGeneric(gv)) + { + gv = outerGeneric; + } + + gv->mangledName = name; + } + + void setMangledName(IRGlobalValue* inst, String const& name) + { + setMangledName(inst, context->getSession()->getNameObj(name)); + } + LoweredValInfo visitAggTypeDecl(AggTypeDecl* decl) { + // Don't generate an IR `struct` for intrinsic types + if(decl->FindModifier<IntrinsicTypeModifier>() || decl->FindModifier<BuiltinTypeModifier>()) + { + return LoweredValInfo(); + } + + if(getMangledName(decl) == "_ST03int") + { + decl = decl; + } + // Given a declaration of a type, we need to make sure // to output "witness tables" for any interfaces this // type has declared conformance to. @@ -3153,13 +3438,92 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> ensureDecl(context, inheritanceDecl); } - // TODO: we currently store a Decl* in the witness table, which causes this function - // being invoked to translate the witness table entry into an IRInst. - // We should really allow a witness table entry to represent a type and not having to - // construct the type here. The current implementation will not work when the struct type - // is defined in a generic parent (we lose the environmental substitutions). - return LoweredValInfo::simple(context->irBuilder->getTypeVal(DeclRefType::Create(context->getSession(), - DeclRef<Decl>(decl, nullptr)))); + // We are going to create nested IR building state + // to use when emitting the members of the type. + // + IRBuilder subBuilderStorage = *getBuilder(); + IRBuilder* subBuilder = &subBuilderStorage; + + // Emit any generics that should wrap the actual type. + emitOuterGenerics(subBuilder, decl, decl); + + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->irBuilder = subBuilder; + + IRStructType* irStruct = subBuilder->createStructType(); + + setMangledName(irStruct, getMangledName(decl)); + + subBuilder->setInsertInto(irStruct); + + for (auto fieldDecl : decl->getMembersOfType<StructField>()) + { + if (fieldDecl->HasModifier<HLSLStaticModifier>()) + { + // A `static` field is actually a global variable, + // and we should emit it as such. + ensureDecl(context, fieldDecl); + continue; + } + + // Each ordinary field will need to turn into a struct "key" + // that is used for fetching the field. + IRInst* fieldKeyInst = getSimpleVal(context, + ensureDecl(context, fieldDecl)); + auto fieldKey = as<IRStructKey>(fieldKeyInst); + assert(fieldKey); + + // Note: we lower the type of the field in the "sub" + // context, so that any generic parameters that were + // set up for the type can be referenced by the field type. + IRType* fieldType = lowerType( + subContext, + fieldDecl->getType()); + + // Then, the parent `struct` instruction itself will have + // a "field" instruction. + subBuilder->createStructField( + irStruct, + fieldKey, + fieldType); + } + + // TODO: we should enumerate the non-field members of the type + // as well, and ensure those have been emitted (e.g., any + // member functions). + + irStruct->moveToEnd(); + + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irStruct)); + } + + LoweredValInfo visitStructField(StructField* fieldDecl) + { + // Each field declaration in the AST translates into + // a "key" that can be used to extract field values + // from instances of struct types that contain the field. + // + // It is correct to say struct *types* because a `struct` + // nested under a generic can be used to realize a number + // of different concrete types, but all of these types + // will use the same space of keys. + + auto builder = getBuilder(); + auto irFieldKey = builder->createStructKey(); + + addVarDecorations(context, irFieldKey, fieldDecl); + + irFieldKey->mangledName = context->getSession()->getNameObj( + getMangledName(fieldDecl)); + + if (auto semanticModifier = fieldDecl->FindModifier<HLSLSimpleSemantic>()) + { + auto semanticDecoration = builder->addDecoration<IRSemanticDecoration>(irFieldKey); + semanticDecoration->semanticName = semanticModifier->name.getName(); + } + + return LoweredValInfo::simple(irFieldKey); } @@ -3227,7 +3591,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> struct ParameterInfo { // This AST-level type of the parameter - Type* type; + RefPtr<Type> type; // The direction (`in` vs `out` vs `in out`) ParameterDirection direction; @@ -3283,7 +3647,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> struct ParameterLists { List<ParameterInfo> params; - List<Decl*> genericParams; }; // // Because there might be a `static` declaration somewhere @@ -3381,7 +3744,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // we need to specialize it for any generic parameters // that are in scope here. auto declRef = createDefaultSpecializedDeclRef(typeDecl); - auto type = DeclRefType::Create(context->getSession(), declRef); + RefPtr<Type> type = DeclRefType::Create(context->getSession(), declRef); addThisParameter( type, ioParameterLists); @@ -3441,51 +3804,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } } } - else if( auto genericDecl = dynamic_cast<GenericDecl*>(decl) ) - { - for( auto memberDecl : genericDecl->Members ) - { - if( auto genericTypeParamDecl = memberDecl.As<GenericTypeParamDecl>() ) - { - ioParameterLists->genericParams.Add(genericTypeParamDecl); - } - else if( auto genericValueParamDecl = memberDecl.As<GenericValueParamDecl>() ) - { - ioParameterLists->genericParams.Add(genericValueParamDecl); - } - else if( auto genericConstraintDel = memberDecl.As<GenericTypeConstraintDecl>() ) - { - // When lowering to the IR we need to reify the constraints on - // a generic parameter as concrete parameters of their own. - // These parameter will usually be satisfied by passing a "witness" - // as the argument to correspond to the parameter. - // - // TODO: it is possible that all witness parameters should come - // after the other generic parameters, and thus should be collected - // in a third list. - // - ioParameterLists->genericParams.Add(genericConstraintDel); - } - } - } - - } - - void trySetMangledName( - IRFunc* irFunc, - Decl* decl) - { - // We want to generate a mangled name for the given declaration and attach - // it to the instruction. - // - // TODO: we probably want to start be doing an early-exit in cases - // where it doesn't make sense to attach a mangled name (e.g., because - // the declaration in question shouldn't have linkage). - // - - String mangledName = getMangledName(decl); - - irFunc->mangledName = context->getSession()->getNameObj(mangledName); } ModuleDecl* findModuleDecl(Decl* decl) @@ -3545,18 +3863,148 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return false; } - RefPtr<Type> maybeGetConstExprType(Type* type, Decl* decl) + IRType* maybeGetConstExprType(IRType* type, Decl* decl) { if(isConstExprVar(decl)) { - return context->getSession()->getConstExprType(type); + return getBuilder()->getRateQualifiedType( + getBuilder()->getConstExprRate(), + type); } return type; } + IRGeneric* emitOuterGeneric( + IRBuilder* subBuilder, + GenericDecl* genericDecl, + Decl* leafDecl) + { + // Of course, a generic might itself be nested inside of other generics... + auto nextOuterGeneric = emitOuterGenerics(subBuilder, genericDecl, leafDecl); + + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->irBuilder = subBuilder; + + + // We need to create an IR generic + + auto irGeneric = subBuilder->emitGeneric(); + subBuilder->setInsertInto(irGeneric); + + if (!nextOuterGeneric) + { + // If this is the outer-most generic, then it will be the + // global symbol that gets the mangled name from the inner + // declaration actually being lowered. + irGeneric->mangledName = context->getSession()->getNameObj(getMangledName(leafDecl)); + } + + auto irBlock = subBuilder->emitBlock(); + subBuilder->setInsertInto(irBlock); + + // Now emit any parameters of the generic + // + // First we start with type and value parameters, + // in the order they were declared. + for (auto member : genericDecl->Members) + { + if (auto typeParamDecl = member.As<GenericTypeParamDecl>()) + { + // TODO: use a `TypeKind` to represent the + // classifier of the parameter. + auto param = subBuilder->emitParam(nullptr); + setValue(subContext, typeParamDecl, LoweredValInfo::simple(param)); + } + else if (auto valDecl = member.As<GenericValueParamDecl>()) + { + auto paramType = lowerType(subContext, valDecl->getType()); + auto param = subBuilder->emitParam(paramType); + setValue(subContext, valDecl, LoweredValInfo::simple(param)); + } + } + // Then we emit constraint parameters, again in + // declaration order. + for (auto member : genericDecl->Members) + { + if (auto constraintDecl = member.As<GenericTypeConstraintDecl>()) + { + // TODO: use a `WitnessTableKind` to represent the + // classifier of the parameter. + auto param = subBuilder->emitParam(nullptr); + setValue(subContext, constraintDecl, LoweredValInfo::simple(param)); + } + } + + return irGeneric; + } + + // If the given `decl` is enclosed in any generic declarations, then + // emit IR-level generics to represent them. + // The `leafDecl` represents the inner-most declaration we are actually + // trying to emit, which is the one that should receive the mangled name. + // + IRGeneric* emitOuterGenerics(IRBuilder* subBuilder, Decl* decl, Decl* leafDecl) + { + for(auto pp = decl->ParentDecl; pp; pp = pp->ParentDecl) + { + if(auto genericAncestor = dynamic_cast<GenericDecl*>(pp)) + { + return emitOuterGeneric(subBuilder, genericAncestor, leafDecl); + } + } + + return nullptr; + } + + // If any generic declarations have been created by `emitOuterGenerics`, + // then finish them off by emitting `return` instructions for the + // values that they should produce. + // + // Return the outer-most generic (if there is one), or the original + // value (if there were no generics), which should be the IR-level + // representation of the original declaration. + // + IRInst* finishOuterGenerics( + IRBuilder* subBuilder, + IRInst* val) + { + IRInst* v = val; + for(;;) + { + auto parentBlock = as<IRBlock>(v->getParent()); + if (!parentBlock) break; + + auto parentGeneric = as<IRGeneric>(parentBlock->getParent()); + if (!parentGeneric) break; + + subBuilder->setInsertInto(parentBlock); + subBuilder->emitReturn(v); + parentGeneric->moveToEnd(); + + // There might be more outer generics, + // so we need to loop until we run out. + v = parentGeneric; + } + return v; + } + LoweredValInfo lowerFuncDecl(FunctionDeclBase* decl) { + // We are going to use a nested builder, because we will + // change the parent node that things get nested into. + + IRBuilder subBuilderStorage = *getBuilder(); + IRBuilder* subBuilder = &subBuilderStorage; + + + // The actual `IRFunction` that we emit needs to be nested + // inside of one `IRGeneric` for every outer `GenericDecl` + // in the declaration hierarchy. + + emitOuterGenerics(subBuilder, decl, decl); + // Collect the parameter lists we will use for our new function. ParameterLists parameterLists; collectParameterLists(decl, ¶meterLists, kParameterListCollectMode_Default); @@ -3584,9 +4032,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; - IRGenContext subContextStorage = *context; IRGenContext* subContext = &subContextStorage; subContext->irBuilder = subBuilder; @@ -3594,27 +4039,14 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // need to create an IR function here IRFunc* irFunc = subBuilder->createFunc(); - subBuilder->setInsertInto(irFunc); - trySetMangledName(irFunc, decl); + setMangledName(irFunc, getMangledName(decl)); - List<RefPtr<Type>> paramTypes; + List<IRType*> paramTypes; - // We first need to walk the generic parameters (if any) - // because these will influence the declared type of - // the function. - - for(auto pp = decl->ParentDecl; pp; pp = pp->ParentDecl) - { - if(auto genericAncestor = dynamic_cast<GenericDecl*>(pp)) - { - irFunc->genericDecls.Add(genericAncestor); - } - } - irFunc->specializedGenericLevel = (int)irFunc->genericDecls.Count() - 1; for( auto paramInfo : parameterLists.params ) { - RefPtr<Type> irParamType = lowerSimpleType(context, paramInfo.type); + IRType* irParamType = lowerType(subContext, paramInfo.type); switch( paramInfo.direction ) { @@ -3627,10 +4059,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // the IR, but we will use a specialized pointer // type that encodes the parameter direction information. case kParameterDirection_Out: - irParamType = context->getSession()->getOutType(irParamType); + irParamType = subBuilder->getOutType(irParamType); break; case kParameterDirection_InOut: - irParamType = context->getSession()->getInOutType(irParamType); + irParamType = subBuilder->getInOutType(irParamType); break; default: @@ -3649,7 +4081,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> paramTypes.Add(irParamType); } - auto irResultType = lowerSimpleType(context, declForReturnType->ReturnType); + auto irResultType = lowerType(subContext, declForReturnType->ReturnType); if (auto setterDecl = dynamic_cast<SetterDecl*>(decl)) { @@ -3663,22 +4095,23 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // Instead, a setter always returns `void` // - irResultType = context->getSession()->getVoidType(); + irResultType = subBuilder->getVoidType(); } if( auto refAccessorDecl = dynamic_cast<RefAccessorDecl*>(decl) ) { // A `ref` accessor needs to return a *pointer* to the value // being accessed, rather than a simple value. - irResultType = context->getSession()->getPtrType(irResultType); + irResultType = subBuilder->getPtrType(irResultType); } - auto irFuncType = getFuncType( - context, + auto irFuncType = subBuilder->getFuncType( paramTypes.Count(), paramTypes.Buffer(), irResultType); - irFunc->type = irFuncType; + irFunc->setFullType(irFuncType); + + subBuilder->setInsertInto(irFunc); if (isImportedDecl(decl)) { @@ -3788,8 +4221,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> if( auto paramDecl = paramInfo.decl ) { - DeclRef<VarDeclBase> paramDeclRef = makeDeclRef(paramDecl); - subContext->shared->declValues[paramDeclRef] = paramVal; + setValue(subContext, paramDecl, paramVal); } if (paramInfo.isThisParam) @@ -3816,7 +4248,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // of the body, in case the user didn't do so. if (!subContext->irBuilder->getBlock()->getTerminator()) { - if (irResultType->Equals(context->getSession()->getVoidType())) + if(as<IRVoidType>(irResultType)) { // `void`-returning function can get an implicit // return on exit of the body statement. @@ -3872,7 +4304,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // of global values. irFunc->moveToEnd(); - return LoweredValInfo::simple(irFunc); + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irFunc)); } LoweredValInfo visitGenericDecl(GenericDecl * genDecl) @@ -3937,8 +4369,15 @@ LoweredValInfo lowerDecl( { IRBuilderSourceLocRAII sourceLocInfo(context->irBuilder, decl->loc); + IRGenEnv subEnv; + subEnv.outer = context->env; + + IRGenContext subContext = *context; + subContext.env = &subEnv; + + DeclLoweringVisitor visitor; - visitor.context = context; + visitor.context = &subContext; return visitor.dispatch(decl); } @@ -3950,11 +4389,21 @@ LoweredValInfo ensureDecl( auto shared = context->shared; LoweredValInfo result; - if(shared->declValues.TryGetValue(decl, result)) - return result; + + // Look for an existing value installed in this context + auto env = context->env; + while(env) + { + if(env->mapDeclToValue.TryGetValue(decl, result)) + return result; + + env = env->outer; + } + IRBuilder subIRBuilder; subIRBuilder.sharedBuilder = context->irBuilder->sharedBuilder; + subIRBuilder.setInsertInto(subIRBuilder.sharedBuilder->module->getModuleInst()); IRGenContext subContext = *context; @@ -3962,225 +4411,189 @@ LoweredValInfo ensureDecl( result = lowerDecl(&subContext, decl); - shared->declValues[decl] = result; + // By default assume that any value we are lowering represents + // something that should be installed globally. + setGlobalValue(shared, decl, result); return result; } -IRInst* findWitnessTable( +IRInst* lowerSubstitutionArg( IRGenContext* context, - DeclRef<Decl> declRef) + Val* val) { - IRInst* irVal = getSimpleVal(context, emitDeclRef(context, declRef)); - if (!irVal) + if (auto type = dynamic_cast<Type*>(val)) { - SLANG_UNEXPECTED("expected a witness table"); - return nullptr; + return lowerType(context, type); } - - if (irVal->op == kIROp_specialize) + else if (auto declaredSubtypeWitness = dynamic_cast<DeclaredSubtypeWitness*>(val)) { - return irVal; + // We need to look up the IR-level representation of the witness (which will be a witness table). + auto irWitnessTable = getSimpleVal( + context, + emitDeclRef( + context, + declaredSubtypeWitness->declRef, + context->irBuilder->getWitnessTableType())); + return irWitnessTable; } - - if (irVal->op != kIROp_witness_table) + else { - SLANG_UNEXPECTED("expected a witness table"); - return nullptr; + SLANG_UNIMPLEMENTED_X("value cases"); } - - return (IRWitnessTable*)irVal; } -RefPtr<Val> lowerSubstitutionArg( - IRGenContext* context, - Val* val) +// Can the IR lowered version of this declaration ever be an `IRGeneric`? +bool canDeclLowerToAGeneric(RefPtr<Decl> decl) { - if (auto type = dynamic_cast<Type*>(val)) - { - return lowerSimpleType(context, type); - } - else if (auto declaredSubtypeWitness = dynamic_cast<DeclaredSubtypeWitness*>(val)) - { - // We do not have a concrete witness table yet for a GenericTypeConstraintDecl witness + // A callable decl lowers to an `IRFunc`, and can be generic + if(decl.As<CallableDecl>()) return true; - if (declaredSubtypeWitness->declRef.As<GenericTypeConstraintDecl>()) - return val; + // An aggregate type decl lowers to an `IRStruct`, and can be generic + if(decl.As<AggTypeDecl>()) return true; - // We need to look up the IR-level representation of the witness - // (which is a witness table). + // An inheritance decl lowers to an `IRWitnessTable`, and can be generic + if(decl.As<InheritanceDecl>()) return true; - auto irWitnessTable = findWitnessTable(context, declaredSubtypeWitness->declRef); + // A `typedef` declaration nested under a generic will turn into + // a generic that returns a type (a simple type-level function). + if(decl.As<TypeDefDecl>()) return true; - // We have an IR-level value, but we need to embed it into an AST-level - // type, so we will use a proxy `Val` that wraps up an `IRInst` as - // an AST-level value. - // - // TODO: This proxy value currently doesn't enter into use-def chaining, - // and so Bad Things could happen quite easily. We need to fix that - // up in a reasonably clean fashion. - // - RefPtr<IRProxyVal> proxyVal = new IRProxyVal(); - proxyVal->inst.init(nullptr, irWitnessTable); - return proxyVal; - } - else - { - // For now, jsut assume that all other values - // lower to themselves. - // - // TODO: we should probably handle the case of - // a `Val` that references an AST-level `constexpr` - // variable, since that would need to be lowered - // to a `Val` that references the IR equivalent. - return val; - } + return false; } -// Given a set of substitutions, make sure that we have -// lowered the arguments being used into a form that -// is suitable for use in the IR. -RefPtr<GenericSubstitution> lowerGenericSubstitutions( - IRGenContext* context, - GenericSubstitution* genSubst) +LoweredValInfo emitDeclRef( + IRGenContext* context, + RefPtr<Decl> decl, + RefPtr<Substitutions> subst, + IRType* type) { - if(!genSubst) - return nullptr; - RefPtr<GenericSubstitution> result; - RefPtr<GenericSubstitution> newSubst = new GenericSubstitution(); - newSubst->genericDecl = genSubst->genericDecl; + // We need to proceed by considering the specializations that + // have been put in place. - for (auto arg : genSubst->args) - { - auto newArg = lowerSubstitutionArg(context, arg); - newSubst->args.Add(newArg); - } + // Ignore any global generic type substitutions during lowering. + // Really, we don't even expect these to appear. + while(auto globalGenericSubst = subst.As<GlobalGenericParamSubstitution>()) + subst = globalGenericSubst->outer; - result = newSubst; - if (genSubst->outer) + // If the declaration would not get wrapped in a `IRGeneric`, + // even if it is nested inside of an AST `GenericDecl`, then + // we should also ignore any generic substiuttions. + if(!canDeclLowerToAGeneric(decl)) { - result->outer = lowerGenericSubstitutions( - context, - genSubst->outer); + while(auto genericSubst = subst.As<GenericSubstitution>()) + subst = genericSubst->outer; } - return result; -} -RefPtr<GlobalGenericParamSubstitution> lowerGlobalGenericSubstitutions( - IRGenContext* context, - GlobalGenericParamSubstitution* genSubst) -{ - if (!genSubst) - return nullptr; - RefPtr<GlobalGenericParamSubstitution> result; - RefPtr<GlobalGenericParamSubstitution> newSubst = new GlobalGenericParamSubstitution(); - newSubst->actualType = lowerSubstitutionArg(context, genSubst->actualType); - newSubst->paramDecl = genSubst->paramDecl; - for (auto & tbl : genSubst->witnessTables) + // In the simplest case, there is no specialization going + // on, and the decl-ref turns into a reference to the + // lowered IR value for the declaration. + if(!subst) { - auto ntbl = tbl; - ntbl.Value = lowerSubstitutionArg(context, tbl.Value); - newSubst->witnessTables.Add(ntbl); + LoweredValInfo loweredDecl = ensureDecl(context, decl); + return loweredDecl; } - result = newSubst; - if (genSubst->outer) + + // Otherwise, we look at the kind of substitution, and let it guide us. + if(auto genericSubst = subst.As<GenericSubstitution>()) { - result->outer = lowerGlobalGenericSubstitutions( + // A generic substitution means we will need to output + // a `specialize` instruction to specialize the generic. + // + // First we want to emit the value without generic specialization + // applied, to get a correct value for it. + // + // Note: we only "unwrap" a single layer from the + // substitutions here, because the underlying declaration + // might be nested in multiple generics, or it might + // come from an interface. + // + LoweredValInfo genericVal = emitDeclRef( context, - genSubst->outer); - } - return result; -} - -RefPtr<ThisTypeSubstitution> lowerThisTypeSubstitution( - IRGenContext* context, - ThisTypeSubstitution* thisSubst) -{ - if (!thisSubst) - return nullptr; - RefPtr<ThisTypeSubstitution> newSubst = new ThisTypeSubstitution(); - newSubst->sourceType = lowerSubstitutionArg(context, thisSubst->sourceType); - return newSubst; -} - -SubstitutionSet lowerSubstitutions(IRGenContext* context, SubstitutionSet subst) -{ - SubstitutionSet rs; - rs.genericSubstitutions = lowerGenericSubstitutions(context, subst.genericSubstitutions); - rs.thisTypeSubstitution = lowerThisTypeSubstitution(context, subst.thisTypeSubstitution); - rs.globalGenParamSubstitutions = lowerGlobalGenericSubstitutions(context, subst.globalGenParamSubstitutions); - return rs; -} - -LoweredValInfo emitDeclRef( - IRGenContext* context, - DeclRef<Decl> declRef) -{ - // First we need to construct an IR value representing the - // unspecialized declaration. - LoweredValInfo loweredDecl = ensureDecl(context, declRef.getDecl()); - - return maybeEmitSpecializeInst(context, loweredDecl, declRef); -} + decl, + genericSubst->outer, + context->irBuilder->getGenericKind()); -LoweredValInfo maybeEmitSpecializeInst(IRGenContext* context, - LoweredValInfo loweredDecl, - DeclRef<Decl> declRef) -{ - // If this declaration reference doesn't involve any specializations, - // then we are done at this point. - if (!declRef.substitutions.genericSubstitutions) - return loweredDecl; - - // There's no reason to specialize something that maps to a NULL pointer. - if (loweredDecl.flavor == LoweredValInfo::Flavor::None) - return loweredDecl; + // There's no reason to specialize something that maps to a NULL pointer. + if (genericVal.flavor == LoweredValInfo::Flavor::None) + return LoweredValInfo(); - if (!declRef.As<FuncDecl>() && !declRef.As<TypeConstraintDecl>()) - return loweredDecl; + // We can only really specialize things that map to single values. + // It would be an error if we got a non-`None` value that + // wasn't somehow a single value. + auto irGenericVal = getSimpleVal(context, genericVal); - auto val = getSimpleVal(context, loweredDecl); + // We have the IR value for the generic we'd like to specialize, + // and now we need to get the value for the arguments. + List<IRInst*> irArgs; + for (auto argVal : genericSubst->args) + { + auto irArgVal = lowerSimpleVal(context, argVal); + SLANG_ASSERT(irArgVal); + irArgs.Add(irArgVal); + } + // Once we have both the generic and its arguments, + // we can emit a `specialize` instruction and use + // its value as the result. + auto irSpecializedVal = context->irBuilder->emitSpecializeInst( + type, + irGenericVal, + irArgs.Count(), + irArgs.Buffer()); - RefPtr<GenericSubstitution> outterMostSubst, secondOutterMostSubst; - for (auto subst = declRef.substitutions.genericSubstitutions; subst; subst = subst->outer) - { - if (!subst->outer) - outterMostSubst = subst; - else - secondOutterMostSubst = subst; + return LoweredValInfo::simple(irSpecializedVal); } - auto newSubst = outterMostSubst; - // We have the "raw" substitutions from the AST, but we may - // need to walk through those and replace things in - // cases where the `Val`s used for substitution should - // lower to something other than their original form. - SubstitutionSet oldSubst = declRef.substitutions; - oldSubst.genericSubstitutions = newSubst; - auto lowedNewSubst = lowerSubstitutions(context, oldSubst); - DeclRef<Decl> newDeclRef = DeclRef<Decl>(declRef.decl, lowedNewSubst); - - RefPtr<Type> type; - if (auto declType = val->getDataType()) + else if(auto thisTypeSubst = subst.As<ThisTypeSubstitution>()) { - type = declType->Substitute(newDeclRef.substitutions).As<Type>(); + // 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. + // + // The witness table itself is referenced by the this-type + // substitution, so we can just lower that. + // + // Note: unlike the case for generics above, in the interface-lookup + // case, we don't end up caring about any further outer substitutions. + // That is because even if we are naming `ISomething<Foo>.doIt()`, + // a method insided a generic interface, we don't actually care + // about the substitution of `Foo` for the parameter `T` of + // `ISomething<T>`. That is because we really care about the + // witness table for the concrete type that conforms to `ISomething<Foo>`. + // + auto irWitnessTable = lowerSimpleVal(context, thisTypeSubst->witness); + // + // The key to use for looking up the interface member is + // derived from the declaration. + // + auto irRequirementKey = getInterfaceRequirementKey(context, decl); + // + // Those two pieces of information tell us what we need to + // do in order to look up the value that satisfied the requirement. + // + auto irSatisfyingVal = context->irBuilder->emitLookupInterfaceMethodInst( + type, + irWitnessTable, + irRequirementKey); + return LoweredValInfo::simple(irSatisfyingVal); } - - // Otherwise, we need to construct a specialization of the - // given declaration. - auto specializedVal = LoweredValInfo::simple((IRInst*)context->irBuilder->emitSpecializeInst( - type, - val, - newDeclRef)); - if (secondOutterMostSubst) + else { - newDeclRef.substitutions.genericSubstitutions = new GenericSubstitution(*secondOutterMostSubst); - newDeclRef.substitutions.genericSubstitutions->outer = nullptr; - return maybeEmitSpecializeInst(context, specializedVal, newDeclRef); + SLANG_UNEXPECTED("uhandled substitution type"); } - return specializedVal; } +LoweredValInfo emitDeclRef( + IRGenContext* context, + DeclRef<Decl> declRef, + IRType* type) +{ + return emitDeclRef( + context, + declRef.decl, + declRef.substitutions.substitutions, + type); +} static void lowerEntryPointToIR( IRGenContext* context, @@ -4195,10 +4608,34 @@ static void lowerEntryPointToIR( // the entry point request. return; } - // we need to lower all global type arguments as well auto loweredEntryPointFunc = ensureDecl(context, entryPointFuncDecl); - for (auto arg : entryPointRequest->genericParameterTypes) - lowerType(context, arg); + + // Now lower all the arguments supplied for global generic + // type parameters. + // + auto builder = context->irBuilder; + builder->setInsertInto(builder->getModule()->getModuleInst()); + for (RefPtr<Substitutions> subst = entryPointRequest->globalGenericSubst; subst; subst = subst->outer) + { + auto gSubst = subst.As<GlobalGenericParamSubstitution>(); + if(!gSubst) + continue; + + IRInst* typeParam = getSimpleVal(context, ensureDecl(context, gSubst->paramDecl)); + IRType* typeVal = lowerType(context, gSubst->actualType); + + // bind `typeParam` to `typeVal` + builder->emitBindGlobalGenericParam(typeParam, typeVal); + + for (auto& constraintArg : gSubst->constraintArgs) + { + IRInst* constraintParam = getSimpleVal(context, ensureDecl(context, constraintArg.decl)); + IRInst* constraintVal = lowerSimpleVal(context, constraintArg.val); + + // bind `constraintParam` to `constraintVal` + builder->emitBindGlobalGenericParam(constraintParam, constraintVal); + } + } } IRModule* generateIRForTranslationUnit( @@ -4212,11 +4649,9 @@ IRModule* generateIRForTranslationUnit( sharedContext->compileRequest = compileRequest; sharedContext->mainModuleDecl = translationUnit->SyntaxNode; - IRGenContext contextStorage; + IRGenContext contextStorage(sharedContext); IRGenContext* context = &contextStorage; - context->shared = sharedContext; - SharedIRBuilder sharedBuilderStorage; SharedIRBuilder* sharedBuilder = &sharedBuilderStorage; sharedBuilder->module = nullptr; @@ -4251,6 +4686,12 @@ IRModule* generateIRForTranslationUnit( ensureDecl(context, decl); } +#if 0 + fprintf(stderr, "### GENERATED\n"); + dumpIR(module); + fprintf(stderr, "###\n"); +#endif + validateIRModuleIfEnabled(compileRequest, module); // We will perform certain "mandatory" optimization passes now. |
