diff options
Diffstat (limited to 'source/slang/ir-legalize-types.cpp')
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 1047 |
1 files changed, 84 insertions, 963 deletions
diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index 7fad2ccc5..6e909106d 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -1,254 +1,22 @@ // ir-legalize-types.cpp -// This file implements a pass that takes IR -// that has been fully specialized (no more -// generics/interfaces needing to be specialized -// away) and replaces any types that can't actually -// be used as-is on the target. +// This file implements type legalization for the IR. +// It uses the core legalization logic in +// `legalize-types.{h,cpp}` to decide what to do with +// the types, while this file handles the actual +// rewriting of the IR to use the new types. // -// The particular case we are focused on is -// aggregate types (e.g., `struct` types) that -// contain resources (textures, samplers, etc.) -// or that mix resources and ordinary "uniform" -// data. +// This pass should only be applied to IR that has been +// fully specialized (no more generics/interfaces), so +// that the concrete type of everything is known. #include "ir.h" #include "ir-insts.h" +#include "legalize-types.h" namespace Slang { -struct LegalTypeImpl : RefObject -{ -}; -struct ImplicitDerefType; -struct TuplePseudoType; -struct PairPseudoType; -struct PairInfo; - -struct LegalType -{ - enum class Flavor - { - // Nothing: a NULL type - none, - - // A simple type that can be represented directly as a `Type` - simple, - - // Logically, we have a pointer-like type, but we are - // going to represnet it as the pointed-to type - implicitDeref, - - // A compound type was broken apart into its constituent fields, - // so a tuple "pseduo-type" is being used to collect - // those fields together. - tuple, - - // A type has to get split into "ordinary" and "special" parts, - // each of which will be represented with its own `LegalType`. - pair, - }; - - Flavor flavor = Flavor::none; - RefPtr<RefObject> obj; - - static LegalType simple(Type* type) - { - LegalType result; - result.flavor = Flavor::simple; - result.obj = type; - return result; - } - - RefPtr<Type> getSimple() - { - assert(flavor == Flavor::simple); - return obj.As<Type>(); - } - - static LegalType implicitDeref( - LegalType const& valueType); - - RefPtr<ImplicitDerefType> getImplicitDeref() - { - assert(flavor == Flavor::implicitDeref); - return obj.As<ImplicitDerefType>(); - } - - static LegalType tuple( - RefPtr<TuplePseudoType> tupleType); - - RefPtr<TuplePseudoType> getTuple() - { - assert(flavor == Flavor::tuple); - return obj.As<TuplePseudoType>(); - } - - static LegalType pair( - RefPtr<PairPseudoType> pairType); - - static LegalType pair( - RefPtr<Type> ordinaryType, - LegalType const& specialType, - RefPtr<PairInfo> pairInfo); - - RefPtr<PairPseudoType> getPair() - { - assert(flavor == Flavor::pair); - return obj.As<PairPseudoType>(); - } -}; - -struct ImplicitDerefType : LegalTypeImpl -{ - LegalType valueType; -}; - -LegalType LegalType::implicitDeref( - LegalType const& valueType) -{ - RefPtr<ImplicitDerefType> obj = new ImplicitDerefType(); - obj->valueType = valueType; - - LegalType result; - result.flavor = Flavor::implicitDeref; - result.obj = obj; - return result; -} - -// Represents the pseudo-type for a compound type -// that had to be broken apart because it contained -// one or more fields of types that shouldn't be -// allowed in aggregates. -// -// A tuple pseduo-type will have an element for -// each field of the original type, that represents -// the legalization of that field's type. -// -// It optionally also contains an "ordinary" type -// that packs together any per-field data that -// itself has (or contains) an ordinary type. -struct TuplePseudoType : LegalTypeImpl -{ - // Represents one element of the tuple pseudo-type - struct Element - { - // The field that this element replaces - DeclRef<VarDeclBase> fieldDeclRef; - - // The legalized type of the element - LegalType type; - }; - - // All of the elements of the tuple pseduo-type. - List<Element> elements; -}; - -LegalType LegalType::tuple( - RefPtr<TuplePseudoType> tupleType) -{ - LegalType result; - result.flavor = Flavor::tuple; - result.obj = tupleType; - return result; -} - -struct PairInfo : RefObject -{ - typedef unsigned int Flags; - enum - { - kFlag_hasOrdinary = 0x1, - kFlag_hasSpecial = 0x2, - }; - - struct Element - { - // The field the element represents - DeclRef<Decl> fieldDeclRef; - - // The conceptual type of the field. - // If both the `hasOrdinary` and - // `hasSpecial` bits are set, then - // this is expected to be a - // `LegalType::Flavor::pair` - LegalType type; - - // Is the value represented on - // the ordinary side, the special - // side, or both? - Flags flags; - }; - - // For a pair type or value, we need to track - // which fields are on which side(s). - List<Element> elements; - - Element* findElement(DeclRef<Decl> const& fieldDeclRef) - { - for (auto& ee : elements) - { - if(ee.fieldDeclRef.Equals(fieldDeclRef)) - return ⅇ - } - return nullptr; - } -}; - -struct PairPseudoType : LegalTypeImpl -{ - // Any field(s) with ordinary types will - // get captured here, as a completely - // standard AST-level type. - RefPtr<Type> ordinaryType; - - // Any fields with "special" (not ordinary) - // types will get captured here (usually - // with a tuple). - LegalType specialType; - - RefPtr<PairInfo> pairInfo; -}; - -LegalType LegalType::pair( - RefPtr<PairPseudoType> pairType) -{ - LegalType result; - result.flavor = Flavor::pair; - result.obj = pairType; - return result; -} - -LegalType LegalType::pair( - RefPtr<Type> ordinaryType, - LegalType const& specialType, - RefPtr<PairInfo> pairInfo) -{ - // Handle some special cases for when - // one or the other of the types isn't - // actually used. - - if (!ordinaryType) - { - // There was nothing ordinary. - return specialType; - } - - if (specialType.flavor == LegalType::Flavor::none) - { - return LegalType::simple(ordinaryType); - } - - // There were both ordinary and special fields, - // and so we need to handle them here. - - RefPtr<PairPseudoType> obj = new PairPseudoType(); - obj->ordinaryType = ordinaryType; - obj->specialType = specialType; - obj->pairInfo = pairInfo; - return LegalType::pair(obj); -} struct LegalValImpl : RefObject @@ -390,12 +158,15 @@ LegalVal LegalVal::getImplicitDeref() } -struct TypeLegalizationContext +struct IRTypeLegalizationContext { Session* session; IRModule* module; IRBuilder* builder; + /// Context to use for underlying (non-IR) type legalization. + TypeLegalizationContext* typeLegalizationContext; + // When inserting new globals, put them before this one. IRGlobalValue* insertBeforeGlobal = nullptr; @@ -411,633 +182,31 @@ struct TypeLegalizationContext }; static void registerLegalizedValue( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRValue* irValue, LegalVal const& legalVal) { context->mapValToLegalVal.Add(irValue, legalVal); } - -static bool isResourceType(Type* type) -{ - while (auto arrayType = type->As<ArrayExpressionType>()) - { - type = arrayType->baseType; - } - - if (auto textureTypeBase = type->As<TextureTypeBase>()) - { - return true; - } - else if (auto samplerType = type->As<SamplerStateType>()) - { - return true; - } - - // TODO: need more comprehensive coverage here - - return false; -} - -static LegalType legalizeType( - TypeLegalizationContext* context, - Type* type); - -// Helper type for legalization of aggregate types -// that might need to be turned into tuple pseudo-types. -struct TupleTypeBuilder -{ - TypeLegalizationContext* context; - RefPtr<Type> type; - - List<FilteredTupleType::Element> ordinaryElements; - List<TuplePseudoType::Element> specialElements; - - List<PairInfo::Element> pairElements; - - // Did we have any fields that forced us to change - // the actual type away from the declared type? - bool anyComplex = false; - - // Did we have any fields that actually required - // storage in the "special" part of things? - bool anySpecial = false; - - // Did we have any fields that actually used ordinary storage? - bool anyOrdinary = false; - - // Add a field to the (pseudo-)type we are building - void addField( - DeclRef<VarDeclBase> fieldDeclRef, - LegalType legalFieldType, - LegalType legalLeafType, - bool isResource) - { - RefPtr<Type> ordinaryType; - LegalType specialType; - RefPtr<PairInfo> elementPairInfo; - switch (legalLeafType.flavor) - { - case LegalType::Flavor::simple: - { - // We need to add an actual field, but we need - // to check if it is a resource type to know - // whether it should go in the "ordinary" list or not. - if (!isResource) - { - ordinaryType = legalLeafType.getSimple(); - } - else - { - specialType = legalFieldType; - } - } - break; - - case LegalType::Flavor::implicitDeref: - { - // TODO: we may want to say that any use - // of `implicitDeref` puts the entire thing - // into the "special" category, rather than - // try to look under the hood... - - anyComplex = true; - - // We want to recursively add data - // based on the unwrapped type. - // - // Note: this assumes we can't have a tuple - // or a pair "under" an `implicitDeref`, so - // we'll need to ensure that elsewhere. - addField( - fieldDeclRef, - legalFieldType, - legalLeafType.getImplicitDeref()->valueType, - isResource); - return; - } - break; - - case LegalType::Flavor::pair: - { - // The field's type had both special and non-special parts - auto pairType = legalLeafType.getPair(); - ordinaryType = pairType->ordinaryType; - specialType = pairType->specialType; - elementPairInfo = pairType->pairInfo; - } - break; - - case LegalType::Flavor::tuple: - { - // A tuple always represents "special" data - specialType = legalFieldType; - } - break; - - default: - SLANG_UNEXPECTED("unknown legal type flavor"); - break; - } - - - PairInfo::Element pairElement; - pairElement.flags = 0; - pairElement.fieldDeclRef = fieldDeclRef; - - if (ordinaryType) - { - anyOrdinary = true; - pairElement.flags |= PairInfo::kFlag_hasOrdinary; - - FilteredTupleType::Element ordinaryElement; - ordinaryElement.fieldDeclRef = fieldDeclRef; - ordinaryElement.type = ordinaryType; - ordinaryElements.Add(ordinaryElement); - } - - if (specialType.flavor != LegalType::Flavor::none) - { - anySpecial = true; - anyComplex = true; - pairElement.flags |= PairInfo::kFlag_hasSpecial; - - TuplePseudoType::Element specialElement; - specialElement.fieldDeclRef = fieldDeclRef; - specialElement.type = specialType; - specialElements.Add(specialElement); - } - - pairElement.type = LegalType::pair(ordinaryType, specialType, elementPairInfo); - pairElements.Add(pairElement); - } - - // Add a field to the (pseudo-)type we are building - void addField( - DeclRef<VarDeclBase> fieldDeclRef) - { - // Skip `static` fields. - if (fieldDeclRef.getDecl()->HasModifier<HLSLStaticModifier>()) - return; - - auto fieldType = GetType(fieldDeclRef); - - bool isResourceField = isResourceType(fieldType); - - auto legalFieldType = legalizeType(context, fieldType); - addField( - fieldDeclRef, - legalFieldType, - legalFieldType, - isResourceField); - } - - LegalType getResult() - { - // If we didn't see anything "special" - // then we can use the type as-is. - // we can conceivably just use the type as-is - // - // TODO: this might be a good place to turn - // a reference to a generic `struct` type into - // a concrete non-generic type so that downstream - // codegen doesn't have to deal with generics... - // - // TODO: In fact, why not just fully replace - // all aggregate types here with some structural - // types defined in the IR? - if (!anyComplex) - { - return LegalType::simple(type); - } - - // If there were any "ordinary" fields along the way, - // then we need to collect them into a type to - // represent the ordinary part of things. - // - RefPtr<Type> ordinaryType; - if (anyOrdinary) - { - RefPtr<FilteredTupleType> ordinaryTypeImpl = new FilteredTupleType(); - ordinaryTypeImpl->setSession(context->session); - ordinaryTypeImpl->originalType = type; - ordinaryTypeImpl->elements = ordinaryElements; - ordinaryType = ordinaryTypeImpl; - } - - LegalType specialType; - if (anySpecial) - { - RefPtr<TuplePseudoType> specialTuple = new TuplePseudoType(); - specialTuple->elements = specialElements; - specialType = LegalType::tuple(specialTuple); - } - - RefPtr<PairInfo> pairInfo; - if (anyOrdinary && anySpecial) - { - pairInfo = new PairInfo(); - pairInfo->elements = pairElements; - } - - return LegalType::pair(ordinaryType, specialType, pairInfo); - } - -}; - -static RefPtr<Type> createBuiltinGenericType( - TypeLegalizationContext* context, - DeclRef<Decl> const& typeDeclRef, - RefPtr<Type> elementType) -{ - // We are going to take the type for the original - // decl-ref and construct a new one that uses - // our new element type as its parameter. - // - // TODO: we should have library code to make - // manipulations like this way easier. - - RefPtr<GenericSubstitution> oldGenericSubst = getGenericSubstitution( - typeDeclRef.substitutions); - SLANG_ASSERT(oldGenericSubst); - - RefPtr<GenericSubstitution> newGenericSubst = new GenericSubstitution(); - - newGenericSubst->outer = oldGenericSubst->outer; - newGenericSubst->genericDecl = oldGenericSubst->genericDecl; - newGenericSubst->args = oldGenericSubst->args; - newGenericSubst->args[0] = elementType; - - auto newDeclRef = DeclRef<Decl>( - typeDeclRef.getDecl(), - newGenericSubst); - - auto newType = DeclRefType::Create( - context->session, - newDeclRef); - - return newType; -} - -// Create a uniform buffer type with a given legalized -// element type. -static LegalType createLegalUniformBufferType( - TypeLegalizationContext* context, - DeclRef<Decl> const& typeDeclRef, - LegalType legalElementType) -{ - switch (legalElementType.flavor) - { - case LegalType::Flavor::simple: - { - // Easy case: we just have a simple element type, - // so we want to create a uniform buffer that wraps it. - return LegalType::simple(createBuiltinGenericType( - context, - typeDeclRef, - legalElementType.getSimple())); - } - break; - - case LegalType::Flavor::implicitDeref: - { - // This is actually an annoying case, because - // we are being asked to convert, e.g.,: - // - // cbuffer Foo { ParameterBlock<Bar> bar; } - // - // into the equivalent of: - // - // cbuffer Foo { Bar bar; } - // - // Which would really require a new `LegalType` that - // would reprerent a resource type with a modified - // element type. - // - // I'm going to attempt to hack this for now. - return LegalType::implicitDeref(createLegalUniformBufferType( - context, - typeDeclRef, - legalElementType.getImplicitDeref()->valueType)); - } - break; - - case LegalType::Flavor::pair: - { - // We assume that the "ordinary" part of things - // will get wrapped in a constant-buffer type, - // and the "special" part needs to be wrapped - // with an `implicitDeref`. - auto pairType = legalElementType.getPair(); - - auto ordinaryType = createBuiltinGenericType( - context, - typeDeclRef, - pairType->ordinaryType); - auto specialType = LegalType::implicitDeref(pairType->specialType); - - return LegalType::pair(ordinaryType, specialType, pairType->pairInfo); - } - - case LegalType::Flavor::tuple: - { - // if we have a tuple type, then it must be representing - // the fields that can't be stored in a buffer anyway, - // so we just need to wrap each of them in an `implicitDeref` - - auto elementPseudoTupleType = legalElementType.getTuple(); - - RefPtr<TuplePseudoType> bufferPseudoTupleType = new TuplePseudoType(); - - // Wrap all the pseudo-tuple elements with `implicitDeref`, - // since they used to be inside a tuple, but aren't any more. - for (auto ee : elementPseudoTupleType->elements) - { - TuplePseudoType::Element newElement; - - newElement.fieldDeclRef = ee.fieldDeclRef; - newElement.type = LegalType::implicitDeref(ee.type); - - bufferPseudoTupleType->elements.Add(newElement); - } - - return LegalType::tuple(bufferPseudoTupleType); - } - break; - - default: - SLANG_UNEXPECTED("unknown legal type flavor"); - UNREACHABLE_RETURN(LegalType()); - break; - } -} - -static LegalType createLegalUniformBufferType( - TypeLegalizationContext* context, - UniformParameterGroupType* uniformBufferType, - LegalType legalElementType) -{ - return createLegalUniformBufferType( - context, - uniformBufferType->declRef, - legalElementType); -} - -// Create a pointer type with a given legalized value type. -static LegalType createLegalPtrType( - TypeLegalizationContext* context, - DeclRef<Decl> const& typeDeclRef, - LegalType legalValueType) -{ - switch (legalValueType.flavor) - { - case LegalType::Flavor::simple: - { - // Easy case: we just have a simple element type, - // so we want to create a uniform buffer that wraps it. - return LegalType::simple(createBuiltinGenericType( - context, - typeDeclRef, - legalValueType.getSimple())); - } - break; - - case LegalType::Flavor::implicitDeref: - { - // We are being asked to create a pointer type to something - // that is implicitly dereferenced, meaning we had: - // - // Ptr(PtrLink(T)) - // - // and now are being asked to make: - // - // Ptr(implicitDeref(LegalT)) - // - // So it seems like we can just create: - // - // implicitDeref(Ptr(LegalT)) - // - // and nobody should really be able to tell the difference, right? - return LegalType::implicitDeref(createLegalPtrType( - context, - typeDeclRef, - legalValueType.getImplicitDeref()->valueType)); - } - break; - - case LegalType::Flavor::pair: - { - // We just need to pointer-ify both sides of the pair. - auto pairType = legalValueType.getPair(); - - auto ordinaryType = createBuiltinGenericType( - context, - typeDeclRef, - pairType->ordinaryType); - auto specialType = createLegalPtrType( - context, - typeDeclRef, - pairType->specialType); - - return LegalType::pair(ordinaryType, specialType, pairType->pairInfo); - } - - case LegalType::Flavor::tuple: - { - // Wrap each of the tuple elements up as a pointer. - auto valuePseudoTupleType = legalValueType.getTuple(); - - RefPtr<TuplePseudoType> ptrPseudoTupleType = new TuplePseudoType(); - - // Wrap all the pseudo-tuple elements with `implicitDeref`, - // since they used to be inside a tuple, but aren't any more. - for (auto ee : valuePseudoTupleType->elements) - { - TuplePseudoType::Element newElement; - - newElement.fieldDeclRef = ee.fieldDeclRef; - newElement.type = createLegalPtrType( - context, - typeDeclRef, - ee.type); - - ptrPseudoTupleType->elements.Add(newElement); - } - - return LegalType::tuple(ptrPseudoTupleType); - } - break; - - default: - SLANG_UNEXPECTED("unknown legal type flavor"); - UNREACHABLE_RETURN(LegalType()); - break; - } -} - -// Legalize a type, including any nested types -// that it transitively contains. -static LegalType legalizeType( - TypeLegalizationContext* context, - Type* type) -{ - if (auto parameterBlockType = type->As<ParameterBlockType>()) - { - // We basically legalize the `ParameterBlock<T>` type - // over to `T`. In order to represent this preoperly, - // we need to be careful to wrap it up in a way that - // tells us to eliminate downstream deferences... - - auto legalElementType = legalizeType(context, - parameterBlockType->getElementType()); - return LegalType::implicitDeref(legalElementType); - } - else if (auto uniformBufferType = type->As<UniformParameterGroupType>()) - { - // We have a `ConstantBuffer<T>` or `TextureBuffer<T>` or - // other pointer-like type that represents uniform parameters. - // We need to pull any resource-type fields out of it, but - // leave the non-resource fields where they are. - - // Legalize the element type to see what we are working with. - auto legalElementType = legalizeType(context, - uniformBufferType->getElementType()); - - switch (legalElementType.flavor) - { - case LegalType::Flavor::simple: - return LegalType::simple(type); - - default: - return createLegalUniformBufferType( - context, - uniformBufferType, - legalElementType); - } - - } - else if (isResourceType(type)) - { - // We assume that any resource types not handled above - // are legal as-is. - return LegalType::simple(type); - } - else if (type->As<BasicExpressionType>()) - { - return LegalType::simple(type); - } - else if (type->As<VectorExpressionType>()) - { - return LegalType::simple(type); - } - else if (type->As<MatrixExpressionType>()) - { - return LegalType::simple(type); - } - else if (auto ptrType = type->As<PtrTypeBase>()) - { - auto legalValueType = legalizeType(context, ptrType->getValueType()); - return createLegalPtrType(context, ptrType->declRef, legalValueType); - } - else if (auto declRefType = type->As<DeclRefType>()) - { - auto declRef = declRefType->declRef; - if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>()) - { - // Look at the (non-static) fields, and - // see if anything needs to be cleaned up. - // The things that need to be "cleaned up" for - // our purposes are: - // - // - Fields of resource type, or any other future - // type we run into that isn't allowed in - // aggregates for at least some targets - // - // - Fields with types that themselves had to - // get legalized. - // - // If we don't run into any of these, we - // can just use the type as-is. Hooray! - // - // Otherwise, we are effectively going to split - // the type apart and create a `TuplePseudoType`. - // Every field of the original type will be - // represented as an element of this pseudo-type. - // Each element will record its `LegalType`, - // and the original field that it was created from. - // An element will also track whether it contains - // any "ordinary" data, and if so, it will remember - // an element index in a real (AST-level, non-pseudo) - // `TupleType` that is used to bundle together - // such fields. - // - // Storing all the simple fields together like this - // obviously adds complexity to the legalization - // pass, but it has important benefits: - // - // - It avoids creating functions with a very large - // number of parameters (when passing a structure - // with many fields), which might confuse downstream - // compilers. - // - // - It avoids applying AOS->SOA conversion to fields - // that don't actually need it, which is basically - // required if we want type layout to work. - // - // - It ensures that we can actually construct a - // constant-buffer type that wraps a legalized - // aggregate type; the ordinary fields will get - // placed inside a new constant-buffer type, - // while the special ones will get left outside. - // - - TupleTypeBuilder builder; - builder.context = context; - builder.type = type; - - - for (auto ff : getMembersOfType<StructField>(aggTypeDeclRef)) - { - builder.addField(ff); - } - - return builder.getResult(); - } - - // TODO: for other declaration-reference types, we really - // need to legalize the types used in substitutions, and - // signal an error if any of them turn out to be non-simple. - // - // The limited cases of types that can handle having non-simple - // types as generic arguments all need to be special-cased here. - // (For example, we can't handle `Texture2D<SomeStructWithTexturesInIt>`. - // - } - - return LegalType::simple(type); -} - -// Represents the "chain" of declarations that -// were followed to get to a variable that we -// are now declaring as a leaf variable. -struct LegalVarChain -{ - LegalVarChain* next; - VarLayout* varLayout; -}; - static LegalVal declareVars( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IROp op, LegalType type, TypeLayout* typeLayout, LegalVarChain* varChain); +static LegalType legalizeType( + IRTypeLegalizationContext* context, + Type* type) +{ + return legalizeType(context->typeLegalizationContext, type); +} + // Legalize a type, and then expect it to // result in a simple type. static RefPtr<Type> legalizeSimpleType( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, Type* type) { auto legalType = legalizeType(context, type); @@ -1056,7 +225,7 @@ static RefPtr<Type> legalizeSimpleType( // Take a value that is being used as an operand, // and turn it into the equivalent legalized value. static LegalVal legalizeOperand( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRValue* irValue) { LegalVal legalVal; @@ -1111,7 +280,7 @@ static void getArgumentValues( } static LegalVal legalizeCall( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRCall* callInst) { // TODO: implement legalization of non-simple return types @@ -1130,7 +299,7 @@ static LegalVal legalizeCall( } static LegalVal legalizeLoad( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, LegalVal legalPtrVal) { switch (legalPtrVal.flavor) @@ -1186,7 +355,7 @@ static LegalVal legalizeLoad( } static LegalVal legalizeStore( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, LegalVal legalPtrVal, LegalVal legalVal) { @@ -1241,19 +410,13 @@ static LegalVal legalizeStore( } static LegalVal legalizeFieldAddress( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, LegalType type, LegalVal legalPtrOperand, - LegalVal legalFieldOperand) + DeclRef<Decl> fieldDeclRef) { auto builder = context->builder; - // We don't expect any legalization to affect - // the "field" argument. - auto fieldOperand = legalFieldOperand.getSimple(); - assert(fieldOperand->op == kIROp_decl_ref); - auto fieldDeclRef = ((IRDeclRef*)fieldOperand)->declRef; - switch (legalPtrOperand.flavor) { case LegalVal::Flavor::simple: @@ -1261,7 +424,7 @@ static LegalVal legalizeFieldAddress( builder->emitFieldAddress( type.getSimple(), legalPtrOperand.getSimple(), - fieldOperand)); + builder->getDeclRefVal(fieldDeclRef))); case LegalVal::Flavor::pair: { @@ -1286,7 +449,7 @@ static LegalVal legalizeFieldAddress( { auto fieldPairType = type.getPair(); fieldPairInfo = fieldPairType->pairInfo; - ordinaryType = LegalType::simple(fieldPairType->ordinaryType); + ordinaryType = fieldPairType->ordinaryType; specialType = fieldPairType->specialType; } @@ -1295,12 +458,27 @@ static LegalVal legalizeFieldAddress( if (pairElement->flags & PairInfo::kFlag_hasOrdinary) { - ordinaryVal = legalizeFieldAddress(context, ordinaryType, pairVal->ordinaryVal, legalFieldOperand); + // Note: the ordinary side of the pair is expected + // to be a filtered `struct` type, and so it will + // have different field declarations than the + // oridinal type. The element of the `PairInfo` + // structure stores the correct field decl-ref to use + // as `ordinaryFieldDeclRef`. + + ordinaryVal = legalizeFieldAddress( + context, + ordinaryType, + pairVal->ordinaryVal, + pairElement->ordinaryFieldDeclRef); } if (pairElement->flags & PairInfo::kFlag_hasSpecial) { - specialVal = legalizeFieldAddress(context, specialType, pairVal->specialVal, legalFieldOperand); + specialVal = legalizeFieldAddress( + context, + specialType, + pairVal->specialVal, + fieldDeclRef); } return LegalVal::pair(ordinaryVal, specialVal, fieldPairInfo); } @@ -1335,8 +513,27 @@ static LegalVal legalizeFieldAddress( } } +static LegalVal legalizeFieldAddress( + IRTypeLegalizationContext* context, + LegalType type, + LegalVal legalPtrOperand, + LegalVal legalFieldOperand) +{ + // We don't expect any legalization to affect + // the "field" argument. + auto fieldOperand = legalFieldOperand.getSimple(); + assert(fieldOperand->op == kIROp_decl_ref); + auto fieldDeclRef = ((IRDeclRef*)fieldOperand)->declRef; + + return legalizeFieldAddress( + context, + type, + legalPtrOperand, + fieldDeclRef); +} + static LegalVal legalizeInst( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRInst* inst, LegalType type, LegalVal const* args) @@ -1370,7 +567,7 @@ RefPtr<VarLayout> findVarLayout(IRValue* value) } static LegalVal legalizeLocalVar( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRVar* irLocalVar) { // Legalize the type for the variable's value @@ -1424,7 +621,7 @@ static LegalVal legalizeLocalVar( } static LegalVal legalizeInst( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRInst* inst) { if (inst->op == kIROp_Var) @@ -1512,7 +709,7 @@ static void addParamType(IRFuncType * ftype, LegalType t) case LegalType::Flavor::pair: { auto pairInfo = t.getPair(); - addParamType(ftype, LegalType::simple(pairInfo->ordinaryType)); + addParamType(ftype, pairInfo->ordinaryType); addParamType(ftype, pairInfo->specialType); } break; @@ -1529,7 +726,7 @@ static void addParamType(IRFuncType * ftype, LegalType t) } static void legalizeFunc( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRFunc* irFunc) { // Overwrite the function's type with @@ -1606,61 +803,13 @@ static void legalizeFunc( } static LegalVal declareSimpleVar( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IROp op, Type* type, TypeLayout* typeLayout, LegalVarChain* varChain) { - RefPtr<VarLayout> varLayout; - if (typeLayout) - { - // We need to construct a layout for the new variable - // that reflects both the type we have given it, as - // well as all the offset information that has accumulated - // along the chain of parent variables. - - // TODO: this logic needs to propagate through semantics... - - varLayout = new VarLayout(); - varLayout->typeLayout = typeLayout; - - for (auto rr : typeLayout->resourceInfos) - { - auto resInfo = varLayout->findOrAddResourceInfo(rr.kind); - - for (auto vv = varChain; vv; vv = vv->next) - { - if (auto parentResInfo = vv->varLayout->FindResourceInfo(rr.kind)) - { - resInfo->index += parentResInfo->index; - resInfo->space += parentResInfo->space; - } - } - } - - // Some of the parent variables might actually contain offsets - // to the `space` or `set` of the field, and we need to apply - // those to all the nested resource infos. - for (auto vv = varChain; vv; vv = vv->next) - { - auto parentSpaceInfo = vv->varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace); - if (!parentSpaceInfo) - continue; - - for (auto& rr : varLayout->resourceInfos) - { - if (rr.kind == LayoutResourceKind::RegisterSpace) - { - rr.index += parentSpaceInfo->index; - } - else - { - rr.space += parentSpaceInfo->index; - } - } - } - } + RefPtr<VarLayout> varLayout = createVarLayout(varChain, typeLayout); DeclRef<VarDeclBase> varDeclRef; if (varChain) @@ -1733,39 +882,8 @@ static LegalVal declareSimpleVar( return legalVarVal; } -static RefPtr<TypeLayout> getDerefTypeLayout( - TypeLayout* typeLayout) -{ - if (!typeLayout) - return nullptr; - - if (auto parameterGroupTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) - { - return parameterGroupTypeLayout->elementTypeLayout; - } - - return typeLayout; -} - -static RefPtr<VarLayout> getFieldLayout( - TypeLayout* typeLayout, - DeclRef<VarDeclBase> fieldDeclRef) -{ - if (!typeLayout) - return nullptr; - - if (auto structTypeLayout = dynamic_cast<StructTypeLayout*>(typeLayout)) - { - RefPtr<VarLayout> fieldLayout; - if (structTypeLayout->mapVarToLayout.TryGetValue(fieldDeclRef.getDecl(), fieldLayout)) - return fieldLayout; - } - - return nullptr; -} - static LegalVal declareVars( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IROp op, LegalType type, TypeLayout* typeLayout, @@ -1798,7 +916,7 @@ static LegalVal declareVars( case LegalType::Flavor::pair: { auto pairType = type.getPair(); - auto ordinaryVal = declareVars(context, op, LegalType::simple(pairType->ordinaryType), typeLayout, varChain); + auto ordinaryVal = declareVars(context, op, pairType->ordinaryType, typeLayout, varChain); auto specialVal = declareVars(context, op, pairType->specialType, typeLayout, varChain); return LegalVal::pair(ordinaryVal, specialVal, pairType->pairInfo); } @@ -1852,7 +970,7 @@ static LegalVal declareVars( } static void legalizeGlobalVar( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRGlobalVar* irGlobalVar) { // Legalize the type for the variable's value @@ -1899,7 +1017,7 @@ static void legalizeGlobalVar( } static void legalizeGlobalValue( - TypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRGlobalValue* irValue) { switch (irValue->op) @@ -1923,7 +1041,7 @@ static void legalizeGlobalValue( } static void legalizeTypes( - TypeLegalizationContext* context) + IRTypeLegalizationContext* context) { auto module = context->module; for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) @@ -1934,7 +1052,8 @@ static void legalizeTypes( void legalizeTypes( - IRModule* module) + TypeLegalizationContext* typeLegalizationContext, + IRModule* module) { auto session = module->session; @@ -1950,13 +1069,15 @@ void legalizeTypes( builder->sharedBuilder = sharedBuilder; - TypeLegalizationContext contextStorage; + IRTypeLegalizationContext contextStorage; auto context = &contextStorage; context->session = session; context->module = module; context->builder = builder; + context->typeLegalizationContext = typeLegalizationContext; + legalizeTypes(context); } |
