diff options
36 files changed, 577 insertions, 595 deletions
diff --git a/source/core/core.natvis b/source/core/core.natvis index d9035e8ba..2448e2c88 100644 --- a/source/core/core.natvis +++ b/source/core/core.natvis @@ -55,33 +55,33 @@ </Type> <Type Name="Slang::Dictionary<*,*>"> - <DisplayString>{{ size={_count} }}</DisplayString> + <DisplayString>{{ size={m_count} }}</DisplayString> <Expand> - <Item Name="[size]">_count</Item> - <Item Name="[capacity]">bucketSizeMinusOne + 1</Item> + <Item Name="[size]">m_count</Item> + <Item Name="[capacity]">m_bucketCountMinusOne + 1</Item> <CustomListItems MaxItemsPerView="5000" ExcludeView="Test"> <Variable Name="iBucket" InitialValue="0" /> - <Variable Name="pBucket" InitialValue="hashMap" /> + <Variable Name="pBucket" InitialValue="m_hashMap" /> <Variable Name="isDeleted" InitialValue="0" /> <Variable Name="isEmpty" InitialValue="0" /> - <Size>_count</Size> - <Exec>pBucket = hashMap</Exec> + <Size>m_count</Size> + <Exec>pBucket = m_hashMap</Exec> <Loop> - <If Condition="iBucket >= bucketSizeMinusOne + 1"> + <If Condition="iBucket >= m_bucketCountMinusOne"> <Break/> </If> <Exec> - isDeleted = marks.m_buffer.m_count > (iBucket*2+1)/32 - ? ((marks.m_buffer.m_buffer[(iBucket*2+1)/32]&(1<<(iBucket*2+1)%32)) != 0) + isDeleted = m_marks.m_buffer.m_count > (iBucket*2+1)/32 + ? ((m_marks.m_buffer.m_buffer[(iBucket*2+1)/32]&(1<<(iBucket*2+1)%32)) != 0) : 0 </Exec> <Exec> - isEmpty = marks.m_buffer.m_count > (iBucket*2)/32 - ? ((marks.m_buffer.m_buffer[(iBucket*2)/32]&(1<<(iBucket*2)%32)) == 0) + isEmpty = m_marks.m_buffer.m_count > (iBucket*2)/32 + ? ((m_marks.m_buffer.m_buffer[(iBucket*2)/32]&(1<<(iBucket*2)%32)) == 0) : 1 </Exec> <If Condition="isDeleted+isEmpty==0"> - <Item>*(hashMap + iBucket)</Item> + <Item>*(m_hashMap + iBucket)</Item> </If> <Exec>iBucket++</Exec> </Loop> @@ -93,21 +93,21 @@ <DisplayString>{{ size={dict._count} }}</DisplayString> <Expand> <LinkedListItems> - <Size>dict._count</Size> - <HeadPointer>dict.kvPairs.head</HeadPointer> + <Size>m_dict._count</Size> + <HeadPointer>m_dict.kvPairs.head</HeadPointer> <NextPointer>next</NextPointer> - <ValueNode>Value</ValueNode> + <ValueNode>value</ValueNode> </LinkedListItems> </Expand> </Type> <Type Name="Slang::OrderedDictionary<*,*>"> - <DisplayString>{{ size={_count} }}</DisplayString> + <DisplayString>{{ size={m_count} }}</DisplayString> <Expand> <LinkedListItems> - <Size>_count</Size> - <HeadPointer>kvPairs.head</HeadPointer> + <Size>m_count</Size> + <HeadPointer>m_kvPairs.head</HeadPointer> <NextPointer>next</NextPointer> - <ValueNode>Value</ValueNode> + <ValueNode>value</ValueNode> </LinkedListItems> </Expand> </Type> diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h index 0350a99d2..2c683abfe 100644 --- a/source/core/slang-dictionary.h +++ b/source/core/slang-dictionary.h @@ -191,20 +191,9 @@ namespace Slang int newSize = (m_bucketCountMinusOne + 1) * 2; if (newSize == 0) { - newSize = 16; + newSize = 64; } - Dictionary<TKey, TValue> newDict; - newDict.m_bucketCountMinusOne = newSize - 1; - newDict.m_hashMap = new KeyValuePair<TKey, TValue>[newSize]; - newDict.m_marks.resizeAndClear(newSize * 2); - if (m_hashMap) - { - for (auto& kvPair : *this) - { - newDict.add(_Move(kvPair)); - } - } - *this = _Move(newDict); + reserve(newSize); } } @@ -344,6 +333,25 @@ namespace Slang m_marks.clear(); } + void reserve(int newSize) + { + if (newSize <= m_bucketCountMinusOne + 1) + return; + + Dictionary<TKey, TValue> newDict; + newDict.m_bucketCountMinusOne = newSize - 1; + newDict.m_hashMap = new KeyValuePair<TKey, TValue>[newSize]; + newDict.m_marks.resizeAndClear(newSize * 2); + if (m_hashMap) + { + for (auto& kvPair : *this) + { + newDict.add(_Move(kvPair)); + } + } + *this = _Move(newDict); + } + TValue* tryGetValueOrAdd(const TKey& key, const TValue& value) { maybeRehash(); @@ -785,7 +793,7 @@ namespace Slang int newSize = (m_bucketCountMinusOne + 1) * 2; if (newSize == 0) { - newSize = 16; + newSize = 128; } OrderedDictionary<TKey, TValue> newDict; newDict.m_bucketCountMinusOne = newSize - 1; diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h index f52b7fcff..02bcb726f 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -270,8 +270,6 @@ class Substitutions: public NodeBase { SLANG_ABSTRACT_AST_CLASS(Substitutions) - // The next outer that this one refines. - Substitutions* outer = nullptr; // Apply a set of substitutions to the bindings in this substitution Substitutions* applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, Substitutions* substOuter, int* ioDiff); @@ -284,20 +282,26 @@ class Substitutions: public NodeBase Substitutions* _applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, Substitutions* substOuter, int* ioDiff); bool _equalsOverride(Substitutions* subst); HashCode _getHashCodeOverride() const; + + Substitutions* getOuter() const { return outer; } +protected: + // The next outer that this one refines. + Substitutions* outer = nullptr; }; class GenericSubstitution : public Substitutions { SLANG_AST_CLASS(GenericSubstitution) +private: // The generic declaration that defines the // parameters we are binding to arguments GenericDecl* genericDecl = nullptr; -private: // The actual values of the arguments List<Val* > args; public: + GenericDecl* getGenericDecl() const { return genericDecl; } List<Val*>& getArgs() { return args; } const List<Val*>& getArgs() const { return args; } @@ -306,24 +310,12 @@ public: bool _equalsOverride(Substitutions* subst); HashCode _getHashCodeOverride() const; - GenericSubstitution(GenericDecl* decl) - { - genericDecl = decl; - } - - GenericSubstitution(GenericDecl* decl, ArrayView<Val*> argVals) + GenericSubstitution(Substitutions* outerSubst, GenericDecl* decl, ArrayView<Val*> argVals) { + outer = outerSubst; genericDecl = decl; args.addRange(argVals); } - - template<typename... TArgs> - GenericSubstitution(GenericDecl* decl, TArgs... inArgs) - { - genericDecl = decl; - addToList(args, inArgs...); - } - }; class ThisTypeSubstitution : public Substitutions @@ -343,9 +335,11 @@ class ThisTypeSubstitution : public Substitutions bool _equalsOverride(Substitutions* subst); HashCode _getHashCodeOverride() const; - ThisTypeSubstitution(InterfaceDecl* inInterfaceDecl, SubtypeWitness* inWitness) + ThisTypeSubstitution(Substitutions* outerSubst, InterfaceDecl* inInterfaceDecl, SubtypeWitness* inWitness) : interfaceDecl(inInterfaceDecl), witness(inWitness) - {} + { + outer = outerSubst; + } }; class Decl; diff --git a/source/slang/slang-ast-builder.cpp b/source/slang/slang-ast-builder.cpp index 7f1b90837..72cb647d5 100644 --- a/source/slang/slang-ast-builder.cpp +++ b/source/slang/slang-ast-builder.cpp @@ -298,7 +298,7 @@ ArrayExpressionType* ASTBuilder::getArrayType(Type* elementType, IntVal* element { auto arrayGenericDecl = as<GenericDecl>(m_sharedASTBuilder->findMagicDecl("ArrayType")); auto arrayTypeDecl = arrayGenericDecl->inner; - auto substitutions = getOrCreate<GenericSubstitution>(arrayGenericDecl, elementType, elementCount); + auto substitutions = getOrCreateGenericSubstitution(nullptr, arrayGenericDecl, elementType, elementCount); result->declRef = getSpecializedDeclRef<Decl>(arrayTypeDecl, substitutions); } return result; @@ -313,7 +313,7 @@ VectorExpressionType* ASTBuilder::getVectorType( { auto vectorGenericDecl = as<GenericDecl>(m_sharedASTBuilder->findMagicDecl("Vector")); auto vectorTypeDecl = vectorGenericDecl->inner; - auto substitutions = getOrCreate<GenericSubstitution>(vectorGenericDecl, elementType, elementCount); + auto substitutions = getOrCreateGenericSubstitution(nullptr, vectorGenericDecl, elementType, elementCount); result->declRef = getSpecializedDeclRef<Decl>(vectorTypeDecl, substitutions); } return result; @@ -327,7 +327,8 @@ DifferentialPairType* ASTBuilder::getDifferentialPairType( auto typeDecl = genericDecl->inner; - auto substitutions = getOrCreate<GenericSubstitution>( + auto substitutions = getOrCreateGenericSubstitution( + nullptr, genericDecl, valueType, primalIsDifferentialWitness); @@ -367,7 +368,8 @@ MeshOutputType* ASTBuilder::getMeshOutputTypeFromModifier( auto typeDecl = genericDecl->inner; - auto substitutions = getOrCreate<GenericSubstitution>( + auto substitutions = getOrCreateGenericSubstitution( + nullptr, genericDecl, elementType, maxElementCount); @@ -392,7 +394,7 @@ DeclRef<Decl> ASTBuilder::getBuiltinDeclRef(const char* builtinMagicTypeName, Va Substitutions* subst = nullptr; if (genericArg) { - subst = getOrCreate<GenericSubstitution>(genericDecl, genericArg); + subst = getOrCreateGenericSubstitution(nullptr, genericDecl, genericArg); } return getSpecializedDeclRef(decl, subst); } @@ -589,6 +591,11 @@ top: return transitiveWitness; } +ThisTypeSubtypeWitness* ASTBuilder::getThisTypeSubtypeWitness(Type* subType, Type* superType) +{ + return getOrCreate<ThisTypeSubtypeWitness>(subType, superType); +} + SubtypeWitness* ASTBuilder::getExtractFromConjunctionSubtypeWitness( Type* subType, Type* superType, diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h index 9aa3a2f8e..479ad6540 100644 --- a/source/slang/slang-ast-builder.h +++ b/source/slang/slang-ast-builder.h @@ -297,12 +297,7 @@ public: return getOrCreate<ConstantIntVal>(type, value); } - DeclRefType* getOrCreateDeclRefType(DeclRefBase* declRef) - { - return getOrCreate<DeclRefType>(declRef); - } - - GenericSubstitution* getOrCreateGenericSubstitution(GenericDecl* decl, const List<Val*>& args, Substitutions* outer) + GenericSubstitution* getOrCreateGenericSubstitution(Substitutions* outer, GenericDecl* decl, ArrayView<Val*> args) { NodeDesc desc; desc.type = GenericSubstitution::kType; @@ -325,6 +320,20 @@ public: return result; } + GenericSubstitution* getOrCreateGenericSubstitution(Substitutions* outer, GenericDecl* decl, const List<Val*>& args) + { + return getOrCreateGenericSubstitution(outer, decl, args.getArrayView()); + } + + template<typename... Args> + GenericSubstitution* getOrCreateGenericSubstitution(Substitutions* outer, GenericDecl* decl, Args... args) + { + List<Val*> vals; + addToList(vals, args...); + return getOrCreateGenericSubstitution(outer, decl, vals.getArrayView()); + } + + ThisTypeSubstitution* getOrCreateThisTypeSubstitution(InterfaceDecl* interfaceDecl, SubtypeWitness* subtypeWitness, Substitutions* outer) { NodeDesc desc; @@ -444,6 +453,9 @@ public: SubtypeWitness* aIsSubtypeOfBWitness, SubtypeWitness* bIsSubtypeOfCWitness); + /// Produce a witness that `ThisType(IFoo) <: IFoo`. + ThisTypeSubtypeWitness* getThisTypeSubtypeWitness(Type* subType, Type* superType); + /// Produce a witness that `T <: L` or `T <: R` given `T <: L&R` SubtypeWitness* getExtractFromConjunctionSubtypeWitness( Type* subType, diff --git a/source/slang/slang-ast-print.cpp b/source/slang/slang-ast-print.cpp index 65c3a23c9..84c521108 100644 --- a/source/slang/slang-ast-print.cpp +++ b/source/slang/slang-ast-print.cpp @@ -176,7 +176,7 @@ void ASTPrinter::_addDeclPathRec(const DeclRef<Decl>& declRef, Index depth) if (genSubst) { SLANG_RELEASE_ASSERT(genSubst); - SLANG_RELEASE_ASSERT(genSubst->genericDecl == parentGenericDeclRef.getDecl()); + SLANG_RELEASE_ASSERT(genSubst->getGenericDecl() == parentGenericDeclRef.getDecl()); // If the name we printed previously was an operator // that ends with `<`, then immediately printing the diff --git a/source/slang/slang-ast-substitutions.cpp b/source/slang/slang-ast-substitutions.cpp index 3bb3f69e1..7b052522e 100644 --- a/source/slang/slang-ast-substitutions.cpp +++ b/source/slang/slang-ast-substitutions.cpp @@ -64,7 +64,7 @@ Substitutions* GenericSubstitution::_applySubstitutionsShallowOverride(ASTBuilde (*ioDiff)++; - auto substSubst = astBuilder->getOrCreateGenericSubstitution(genericDecl, substArgs, substOuter); + auto substSubst = astBuilder->getOrCreateGenericSubstitution(substOuter, genericDecl, substArgs); return substSubst; } diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 9ae253547..0a5eeb65d 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -96,6 +96,7 @@ namespace Slang kConversionCost_CastToInterface = 50, // Conversion that is lossless and keeps the "kind" of the value the same + kConversionCost_BoolToInt = 120, // Converting bool to int has lower cost than other integer types to prevent ambiguity. kConversionCost_RankPromotion = 150, kConversionCost_NoneToOptional = 150, kConversionCost_ValToOptional = 150, diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp index 9b6b439ce..ee5d1d40e 100644 --- a/source/slang/slang-ast-type.cpp +++ b/source/slang/slang-ast-type.cpp @@ -772,10 +772,8 @@ DeclRef<InterfaceDecl> ExtractExistentialType::getSpecializedInterfaceDeclRef() SubtypeWitness* openedWitness = getSubtypeWitness(); - ThisTypeSubstitution* openedThisType = m_astBuilder->create<ThisTypeSubstitution>(); - openedThisType->outer = originalInterfaceDeclRef.getSubst(); - openedThisType->interfaceDecl = interfaceDecl; - openedThisType->witness = openedWitness; + ThisTypeSubstitution* openedThisType = m_astBuilder->getOrCreateThisTypeSubstitution( + interfaceDecl, openedWitness, originalInterfaceDeclRef.getSubst()); DeclRef<InterfaceDecl> specialiedInterfaceDeclRef = m_astBuilder->getSpecializedDeclRef<InterfaceDecl>(interfaceDecl, openedThisType); diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp index 37912bac2..b45300af8 100644 --- a/source/slang/slang-ast-val.cpp +++ b/source/slang/slang-ast-val.cpp @@ -118,7 +118,7 @@ HashCode GenericParamIntVal::_getHashCodeOverride() Val* maybeSubstituteGenericParam(Val* paramVal, Decl* paramDecl, SubstitutionSet subst, int* ioDiff) { // search for a substitution that might apply to us - for (auto s = subst.substitutions; s; s = s->outer) + for (auto s = subst.substitutions; s; s = s->getOuter()) { auto genSubst = as<GenericSubstitution>(s); if (!genSubst) @@ -126,7 +126,7 @@ Val* maybeSubstituteGenericParam(Val* paramVal, Decl* paramDecl, SubstitutionSet // the generic decl associated with the substitution list must be // the generic decl that declared this parameter - auto genericDecl = genSubst->genericDecl; + auto genericDecl = genSubst->getGenericDecl(); if (genericDecl != paramDecl->parentDecl) continue; @@ -261,13 +261,13 @@ Val* DeclaredSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, Sub auto genConstraintDecl = genConstraintDeclRef.getDecl(); // search for a substitution that might apply to us - for (auto s = subst.substitutions; s; s = s->outer) + for (auto s = subst.substitutions; s; s = s->getOuter()) { if (auto genericSubst = as<GenericSubstitution>(s)) { // the generic decl associated with the substitution list must be // the generic decl that declared this parameter - auto genericDecl = genericSubst->genericDecl; + auto genericDecl = genericSubst->getGenericDecl(); if (genericDecl != genConstraintDecl->parentDecl) continue; diff --git a/source/slang/slang-ast-val.h b/source/slang/slang-ast-val.h index 1731a5799..cb4e94ebb 100644 --- a/source/slang/slang-ast-val.h +++ b/source/slang/slang-ast-val.h @@ -407,6 +407,12 @@ class TaggedUnionSubtypeWitness : public SubtypeWitness class ThisTypeSubtypeWitness : public SubtypeWitness { SLANG_AST_CLASS(ThisTypeSubtypeWitness) + + ThisTypeSubtypeWitness(Type* subType, Type* supType) + { + sub = subType; + sup = supType; + } }; /// A witness of the fact that a user provided "__Dynamic" type argument is a diff --git a/source/slang/slang-check-conformance.cpp b/source/slang/slang-check-conformance.cpp index 0eb44399d..2696f798d 100644 --- a/source/slang/slang-check-conformance.cpp +++ b/source/slang/slang-check-conformance.cpp @@ -50,6 +50,18 @@ namespace Slang } SubtypeWitness* SemanticsVisitor::isSubtype( + Type* subType, + Type* superType) + { + SubtypeWitness* result = nullptr; + if (getShared()->tryGetSubtypeWitness(subType, superType, result)) + return result; + result = checkAndConstructSubtypeWitness(subType, superType); + getShared()->cacheSubtypeWitness(subType, superType, result); + return result; + } + + SubtypeWitness* SemanticsVisitor::checkAndConstructSubtypeWitness( Type* subType, Type* superType) { @@ -92,9 +104,6 @@ namespace Slang // For now we are continuing to conflate all the subtype-ish relationships but not // tangling convertibility into it. - // TODO: Evaluate whether it is beneficial to memo-cache - // the results of subtype tests on the `SharedSemanticsContext`. - // In the common case, we can use the pre-computed inheritance information for `subType` // to enumerate all the types it transitively inherits from. // diff --git a/source/slang/slang-check-constraint.cpp b/source/slang/slang-check-constraint.cpp index 2dc263115..22a92bf0a 100644 --- a/source/slang/slang-check-constraint.cpp +++ b/source/slang/slang-check-constraint.cpp @@ -457,7 +457,7 @@ namespace Slang // apply the substitutions we already know... GenericSubstitution* solvedSubst = m_astBuilder->getOrCreateGenericSubstitution( - genericDeclRef.getDecl(), args, genericDeclRef.getSubst()); + genericDeclRef.getSubst(), genericDeclRef.getDecl(), args.getArrayView()); for( auto constraintDecl : genericDeclRef.getDecl()->getMembersOfType<GenericTypeConstraintDecl>() ) { @@ -510,7 +510,7 @@ namespace Slang } resultSubst = m_astBuilder->getOrCreateGenericSubstitution( - genericDeclRef.getDecl(), args, genericDeclRef.getSubst()); + genericDeclRef.getSubst(), genericDeclRef.getDecl(), args); return resultSubst; } @@ -633,7 +633,7 @@ namespace Slang auto fstGen = fst; auto sndGen = snd; // They must be specializing the same generic - if (fstGen->genericDecl != sndGen->genericDecl) + if (fstGen->getGenericDecl() != sndGen->getGenericDecl()) return false; // Their arguments must unify @@ -649,7 +649,7 @@ namespace Slang } // Their "base" specializations must unify - if (!tryUnifySubstitutions(constraints, fstGen->outer, sndGen->outer)) + if (!tryUnifySubstitutions(constraints, fstGen->getOuter(), sndGen->getOuter())) { okay = false; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 5279ca068..5b7777154 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -596,7 +596,7 @@ namespace Slang GenericSubstitution* cachedResult = nullptr; if (astBuilder->m_genericDefaultSubst.tryGetValue(genericDecl, cachedResult)) { - if (cachedResult->outer == outerSubst) + if (cachedResult->getOuter() == outerSubst) return cachedResult; } @@ -648,7 +648,7 @@ namespace Slang } } - GenericSubstitution* genericSubst = astBuilder->getOrCreateGenericSubstitution(genericDecl, args, outerSubst); + GenericSubstitution* genericSubst = astBuilder->getOrCreateGenericSubstitution(outerSubst, genericDecl, args); if (shouldCache) astBuilder->m_genericDefaultSubst[genericDecl] = genericSubst; return genericSubst; @@ -1410,7 +1410,7 @@ namespace Slang if (auto declRefType = as<DeclRefType>(sharedTypeExpr->base)) { auto subst = createDefaultSubstitutions(m_astBuilder, this, declRefType->declRef.getDecl()); - auto newType = m_astBuilder->getOrCreateDeclRefType(m_astBuilder->getSpecializedDeclRef(declRefType->declRef.getDecl(), subst)); + auto newType = DeclRefType::create(m_astBuilder, m_astBuilder->getSpecializedDeclRef(declRefType->declRef.getDecl(), subst)); sharedTypeExpr->base.type = newType; if (auto typetype = as<TypeType>(typeExp.exp->type)) typetype->type = newType; @@ -1470,7 +1470,7 @@ namespace Slang substSet = declRefType->declRef.getSubst(); } } - auto satisfyingType = m_astBuilder->getOrCreateDeclRefType(m_astBuilder->getSpecializedDeclRef(aggTypeDecl, substSet)); + auto satisfyingType = DeclRefType::create(m_astBuilder, m_astBuilder->getSpecializedDeclRef(aggTypeDecl, substSet)); // Helper function to add a `diffType` field into the synthesized type for the original // `member`. @@ -2292,9 +2292,9 @@ namespace Slang } GenericSubstitution* requiredSubst = m_astBuilder->getOrCreateGenericSubstitution( + requiredGenericDeclRef.getSubst(), requiredGenericDeclRef.getDecl(), - requiredSubstArgs, - requiredGenericDeclRef.getSubst()); + requiredSubstArgs); // Now that we have computed a set of specialization arguments that will // specialize the generic requirement at the type parameters of the satisfying @@ -3729,10 +3729,10 @@ namespace Slang // of `This` in the interface as equivalent to the concrete type for the // purpose of signature matching (and similarly for associated types). // - ThisTypeSubstitution* thisTypeSubst = m_astBuilder->create<ThisTypeSubstitution>(); - thisTypeSubst->interfaceDecl = superInterfaceDeclRef.getDecl(); - thisTypeSubst->witness = subTypeConformsToSuperInterfaceWitness; - thisTypeSubst->outer = superInterfaceDeclRef.getSubst(); + ThisTypeSubstitution* thisTypeSubst = m_astBuilder->getOrCreateThisTypeSubstitution( + superInterfaceDeclRef.getDecl(), + subTypeConformsToSuperInterfaceWitness, + superInterfaceDeclRef.getSubst()); auto specializedSuperInterfaceDeclRef = m_astBuilder->getSpecializedDeclRef<InterfaceDecl>(superInterfaceDeclRef.getDecl(), thisTypeSubst); @@ -4871,8 +4871,8 @@ namespace Slang // looks like `T : IFoo`. // auto& substRightToLeft = *outSubstRightToLeft; - substRightToLeft = createDummySubstitutions(left); - substRightToLeft->genericDecl = right; + List<Val*> leftArgs = getDefaultSubstitutionArgs(left); + substRightToLeft = getASTBuilder()->getOrCreateGenericSubstitution(nullptr, right, leftArgs); // We should now be able to enumerate the constraints // on `right` in a way that uses the same type parameters @@ -5014,8 +5014,7 @@ namespace Slang return true; } - GenericSubstitution* SemanticsVisitor::createDummySubstitutions( - GenericDecl* genericDecl) + List<Val*> SemanticsVisitor::getDefaultSubstitutionArgs(GenericDecl* genericDecl) { List<Val*> args; for (auto dd : genericDecl->members) @@ -5053,8 +5052,7 @@ namespace Slang args.add(witness); } } - GenericSubstitution* subst = m_astBuilder->getOrCreateGenericSubstitution(genericDecl, args, nullptr); - return subst; + return args; } typedef Dictionary<Name*, CallableDecl*> TargetDeclDictionary; @@ -6220,10 +6218,10 @@ namespace Slang SLANG_ASSERT(!as<ThisTypeSubstitution>(targetInterfaceDeclRef.getSubst())); // We will create a new substitution to apply to the target type. - ThisTypeSubstitution* newTargetSubst = m_astBuilder->create<ThisTypeSubstitution>(); - newTargetSubst->interfaceDecl = appThisTypeSubst->interfaceDecl; - newTargetSubst->witness = appThisTypeSubst->witness; - newTargetSubst->outer = targetInterfaceDeclRef.getSubst(); + ThisTypeSubstitution* newTargetSubst = m_astBuilder->getOrCreateThisTypeSubstitution( + appThisTypeSubst->interfaceDecl, + appThisTypeSubst->witness, + targetInterfaceDeclRef.getSubst()); targetType = DeclRefType::create(m_astBuilder, m_astBuilder->getSpecializedDeclRef<InterfaceDecl>(targetInterfaceDeclRef.getDecl(), newTargetSubst)); @@ -6235,10 +6233,10 @@ namespace Slang // references to the target type of the extension // declaration have a chance to resolve the way we want them to. - ThisTypeSubstitution* newExtSubst = m_astBuilder->create<ThisTypeSubstitution>(); - newExtSubst->interfaceDecl = appThisTypeSubst->interfaceDecl; - newExtSubst->witness = appThisTypeSubst->witness; - newExtSubst->outer = extDeclRef.getSubst(); + ThisTypeSubstitution* newExtSubst = m_astBuilder->getOrCreateThisTypeSubstitution( + appThisTypeSubst->interfaceDecl, + appThisTypeSubst->witness, + extDeclRef.getSubst()); extDeclRef = m_astBuilder->getSpecializedDeclRef<ExtensionDecl>( extDeclRef.getDecl(), @@ -6533,6 +6531,11 @@ namespace Slang // m_candidateExtensionListsBuilt = false; m_mapTypeDeclToCandidateExtensions.clear(); + + // Invalidate the cached inheritanceInfo. + m_mapTypeToInheritanceInfo.clear(); + m_mapDeclRefToInheritanceInfo.clear(); + m_mapTypePairToSubtypeWitness.clear(); } void SharedSemanticsContext::_addCandidateExtensionsFromModule(ModuleDecl* moduleDecl) @@ -6847,7 +6850,7 @@ namespace Slang { if (auto concreteType = _tryLookupConcreteAssociatedTypeFromThisTypeSubst(m_astBuilder, declRefType->declRef)) return as<Type>(concreteType); - for (auto subst = declRefType->declRef.getSubst(); subst; subst=subst->outer) + for (auto subst = declRefType->declRef.getSubst(); subst; subst=subst->getOuter()) { if (auto genericSubst = as<GenericSubstitution>(subst)) { diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 24f130add..76af3694f 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -539,7 +539,7 @@ namespace Slang auto typeDef = m_astBuilder->create<TypeAliasDecl>(); typeDef->nameAndLoc.name = getName("Differential"); auto declRef = createDefaultSubstitutionsIfNeeded(m_astBuilder, this, makeDeclRef(structDecl)); - typeDef->type.type = m_astBuilder->getOrCreateDeclRefType(declRef); + typeDef->type.type = DeclRefType::create(m_astBuilder, declRef); typeDef->parentDecl = structDecl; structDecl->members.add(typeDef); } @@ -1052,7 +1052,7 @@ namespace Slang { foreachDirectOrExtensionMemberOfType<InheritanceDecl>(this, aggTypeDeclRef, [&](DeclRef<InheritanceDecl> member) { - auto subType = m_astBuilder->getOrCreateDeclRefType(member); + auto subType = DeclRefType::create(m_astBuilder, member); maybeRegisterDifferentiableTypeImplRecursive(m_astBuilder, subType); }); foreachDirectOrExtensionMemberOfType<VarDeclBase>(this, aggTypeDeclRef, [&](DeclRef<VarDeclBase> member) @@ -1061,7 +1061,7 @@ namespace Slang maybeRegisterDifferentiableTypeImplRecursive(m_astBuilder, fieldType); }); } - for (auto subst = declRefType->declRef.getSubst(); subst; subst = subst->outer) + for (auto subst = declRefType->declRef.getSubst(); subst; subst = subst->getOuter()) { if (auto genSubst = as<GenericSubstitution>(subst)) { @@ -1507,7 +1507,7 @@ namespace Slang if (isInterfaceRequirement(decl)) { - for (auto subst = declRef.getSubst(); subst; subst = subst->outer) + for (auto subst = declRef.getSubst(); subst; subst = subst->getOuter()) { if (auto thisTypeSubst = as<ThisTypeSubstitution>(subst)) { diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 709245c28..04112743a 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -613,6 +613,18 @@ namespace Slang /// Get the processed inheritance information for `extension`, including all its facets InheritanceInfo getInheritanceInfo(DeclRef<ExtensionDecl> const& extension); + /// Try get subtype witness from cache, returns true if cache contains a result for the query. + bool tryGetSubtypeWitness(Type* sub, Type* sup, SubtypeWitness*& outWitness) + { + auto pair = TypePair{ sub, sup }; + return m_mapTypePairToSubtypeWitness.tryGetValue(pair, outWitness); + } + void cacheSubtypeWitness(Type* sub, Type* sup, SubtypeWitness*& outWitness) + { + auto pair = TypePair{ sub, sup }; + m_mapTypePairToSubtypeWitness[pair] = outWitness; + } + private: /// Mapping from type declarations to the known extensiosn that apply to them Dictionary<AggTypeDecl*, RefPtr<CandidateExtensionList>> m_mapTypeDeclToCandidateExtensions; @@ -721,8 +733,16 @@ namespace Slang void _mergeFacetLists(DirectBaseList bases, FacetList baseFacets, FacetList::Builder& ioMergedFacets); + struct TypePair + { + Type* type0; + Type* type1; + HashCode getHashCode() const { return combineHash(Slang::getHashCode(type0), Slang::getHashCode(type1)); } + bool operator == (const TypePair& other) const { return type0 == other.type0 && type1 == other.type1; } + }; Dictionary<Type*, InheritanceInfo> m_mapTypeToInheritanceInfo; Dictionary<DeclRef<Decl>, InheritanceInfo> m_mapDeclRefToInheritanceInfo; + Dictionary<TypePair, SubtypeWitness*> m_mapTypePairToSubtypeWitness; }; /// Local/scoped state of the semantic-checking system @@ -1613,7 +1633,7 @@ namespace Slang DeclRef<FuncDecl> fst, DeclRef<FuncDecl> snd); - GenericSubstitution* createDummySubstitutions( + List<Val*> getDefaultSubstitutionArgs( GenericDecl* genericDecl); Result checkRedeclaration(Decl* newDecl, Decl* oldDecl); @@ -1795,6 +1815,8 @@ namespace Slang Type* subType, Type* superType); + SubtypeWitness* checkAndConstructSubtypeWitness(Type* subType, Type* superType); + bool isInterfaceType(Type* type); bool isTypeDifferentiable(Type* type); diff --git a/source/slang/slang-check-inheritance.cpp b/source/slang/slang-check-inheritance.cpp index 8e867b4a7..5a6adbae5 100644 --- a/source/slang/slang-check-inheritance.cpp +++ b/source/slang/slang-check-inheritance.cpp @@ -32,6 +32,9 @@ namespace Slang auto info = _calcInheritanceInfo(type); m_mapTypeToInheritanceInfo[type] = info; + getSession()->m_typeDictionarySize = Math::Max( + getSession()->m_typeDictionarySize, (int)m_mapTypeToInheritanceInfo.getCount()); + return info; } diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 38856d7bf..1d2f82ac7 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -215,10 +215,7 @@ namespace Slang // to represent the arguments that have been coerced to // appropriate forms. // - auto genSubst = m_astBuilder->create<GenericSubstitution>(); - genSubst->genericDecl = genericDeclRef.getDecl(); - candidate.subst = genSubst; - auto& checkedArgs = (List<Val*>&)genSubst->getArgs(); + List<Val*> checkedArgs; // Rather than bail out as soon as we hit a problem, // we are going to process *all* of the parameters of the @@ -348,6 +345,9 @@ namespace Slang } } + auto genSubst = m_astBuilder->getOrCreateGenericSubstitution(nullptr, genericDeclRef.getDecl(), checkedArgs.getArrayView()); + candidate.subst = genSubst; + // Once we are done processing the parameters of the generic, // we will have build up a usable `checkedArgs` array and // can return to the caller a report of whether we @@ -515,8 +515,8 @@ namespace Slang auto subst = as<GenericSubstitution>(candidate.subst); SLANG_ASSERT(subst); - subst->genericDecl = genericDeclRef.getDecl(); - subst->outer = genericDeclRef.getSubst(); + subst = getASTBuilder()->getOrCreateGenericSubstitution( + genericDeclRef.getSubst(), genericDeclRef.getDecl(), subst->getArgs()); List<Val*> newArgs = subst->getArgs(); @@ -544,7 +544,7 @@ namespace Slang } } - candidate.subst = m_astBuilder->getOrCreateGenericSubstitution(genericDeclRef.getDecl(), newArgs, genericDeclRef.getSubst()); + candidate.subst = m_astBuilder->getOrCreateGenericSubstitution(nullptr, genericDeclRef.getDecl(), newArgs); // Done checking all the constraints, hooray. return true; @@ -594,8 +594,7 @@ namespace Slang return CreateErrorExpr(originalExpr); } - subst->genericDecl = baseGenericRef.getDecl(); - subst->outer = baseGenericRef.getSubst(); + subst = m_astBuilder->getOrCreateGenericSubstitution(baseGenericRef.getSubst(), baseGenericRef.getDecl(), subst->getArgs()); DeclRef<Decl> innerDeclRef = m_astBuilder->getSpecializedDeclRef<Decl>(getInner(baseGenericRef), subst); diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp index 382abf081..657438222 100644 --- a/source/slang/slang-check-shader.cpp +++ b/source/slang/slang-check-shader.cpp @@ -1205,9 +1205,9 @@ namespace Slang } GenericSubstitution* genericSubst = getLinkage()->getASTBuilder()->getOrCreateGenericSubstitution( + genericDeclRef.getSubst(), genericDeclRef.getDecl(), - genericArgs, - genericDeclRef.getSubst()); + genericArgs.getArrayView()); ASTBuilder* astBuilder = getLinkage()->getASTBuilder(); for (auto constraintDecl : getMembersOfType<GenericTypeConstraintDecl>( @@ -1235,9 +1235,9 @@ namespace Slang genericSubst = getLinkage()->getASTBuilder()->getOrCreateGenericSubstitution( + genericDeclRef.getSubst(), genericDeclRef.getDecl(), - genericArgs, - genericDeclRef.getSubst()); + genericArgs); specializedFuncDeclRef = astBuilder->getSpecializedDeclRef(specializedFuncDeclRef.getDecl(), genericSubst); } diff --git a/source/slang/slang-check-type.cpp b/source/slang/slang-check-type.cpp index d62d60db4..fd4c218fa 100644 --- a/source/slang/slang-check-type.cpp +++ b/source/slang/slang-check-type.cpp @@ -188,7 +188,7 @@ namespace Slang } GenericSubstitution* subst = m_astBuilder->getOrCreateGenericSubstitution( - genericDeclRef.getDecl(), evaledArgs, genericDeclRef.getSubst()); + genericDeclRef.getSubst(), genericDeclRef.getDecl(), evaledArgs); DeclRef<Decl> innerDeclRef = m_astBuilder->getSpecializedDeclRef(getInner(genericDeclRef), subst); return DeclRefType::create(m_astBuilder, innerDeclRef); diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index df9f52010..ca16bfb94 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -3062,6 +3062,7 @@ namespace Slang /// For parsing command line options CommandOptions m_commandOptions; + int m_typeDictionarySize = 0; private: void _initCodeGenTransitionMap(); diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 55ed78a50..c2d7ba95f 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -3574,43 +3574,32 @@ struct IRTypeLegalizationPass // In order to process an entire module, we start by adding the // root module insturction to our work list, and then we will // proceed to process instructions until the work list goes dry. - // The entire process is repeated until no more changes can be - // made to the module. - // - for (;;) + + addToWorkList(module->getModuleInst()); + while( workList.getCount() != 0 ) { - auto lastReplacedInstCount = context->replacedInstructions.getCount(); - addToWorkList(module->getModuleInst()); - while( workList.getCount() != 0 ) - { - // The order of items in the work list is signficiant; - // later entries could depend on earlier ones. As such, we - // cannot just do something like the `fastRemoveAt(...)` - // operation that could potentially lead to instructions - // being processed in a different order than they were added. - // - // Instead, we will make a copy of the current work list - // at each step, and swap in an empty work list to be added - // to with any new instructions. - // - List<IRInst*> workListCopy; - Swap(workListCopy, workList); + // The order of items in the work list is signficiant; + // later entries could depend on earlier ones. As such, we + // cannot just do something like the `fastRemoveAt(...)` + // operation that could potentially lead to instructions + // being processed in a different order than they were added. + // + // Instead, we will make a copy of the current work list + // at each step, and swap in an empty work list to be added + // to with any new instructions. + // + List<IRInst*> workListCopy = _Move(workList); - resetScratchDataBit(module->getModuleInst(), kHasBeenAddedScratchBitIndex); + resetScratchDataBit(module->getModuleInst(), kHasBeenAddedScratchBitIndex); - // Now we simply process each instruction on the copy of - // the work list, knowing that `processInst` may add additional - // instructions to the original work list. - // - for( auto inst : workListCopy ) - { - processInst(inst); - } + // Now we simply process each instruction on the copy of + // the work list, knowing that `processInst` may add additional + // instructions to the original work list. + // + for( auto inst : workListCopy ) + { + processInst(inst); } - - // Any changes made? Run the process again. - if (lastReplacedInstCount == context->replacedInstructions.getCount()) - break; } // After we are done, there might be various instructions that diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp index 31ac7850a..3edc373c4 100644 --- a/source/slang/slang-ir-lower-generic-function.cpp +++ b/source/slang/slang-ir-lower-generic-function.cpp @@ -175,6 +175,7 @@ namespace Slang { auto paramType = funcType->getOperand(i); auto loweredParamType = sharedContext->lowerType(builder, paramType, typeMapping, nullptr); + SLANG_ASSERT(loweredParamType); translated = translated || (loweredParamType != paramType); newOperands.add(loweredParamType); } diff --git a/source/slang/slang-ir-redundancy-removal.cpp b/source/slang/slang-ir-redundancy-removal.cpp index bac39a53c..e0bb0b224 100644 --- a/source/slang/slang-ir-redundancy-removal.cpp +++ b/source/slang/slang-ir-redundancy-removal.cpp @@ -10,6 +10,10 @@ struct RedundancyRemovalContext RefPtr<IRDominatorTree> dom; bool isMovableInst(IRInst* inst) { + // Don't try to modify hoistable insts, they are already globally deduplicated. + if (getIROpInfo(inst->getOp()).isHoistable()) + return false; + switch (inst->getOp()) { case kIROp_Add: @@ -73,11 +77,6 @@ struct RedundancyRemovalContext case kIROp_ExtractExistentialType: case kIROp_ExtractExistentialValue: case kIROp_ExtractExistentialWitnessTable: - case kIROp_PtrType: - case kIROp_ArrayType: - case kIROp_FuncType: - case kIROp_InOutType: - case kIROp_OutType: return true; case kIROp_Call: return isPureFunctionalCall(as<IRCall>(inst)); diff --git a/source/slang/slang-ir-simplify-cfg.cpp b/source/slang/slang-ir-simplify-cfg.cpp index 0c068bc66..ab332fd1b 100644 --- a/source/slang/slang-ir-simplify-cfg.cpp +++ b/source/slang/slang-ir-simplify-cfg.cpp @@ -509,7 +509,11 @@ static bool simplifyBoolPhiParams(IRBlock* block) Array<IRBlock*, 2> preds; for (auto pred : block->getPredecessors()) + { + if (pred->getTerminator()->getOp() != kIROp_unconditionalBranch) + return false; preds.add(pred); + } IRBlock* ifElseBlock = nullptr; if (preds[0]->getPredecessors().getCount() != 1) diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp index 26f54a271..a806a13e6 100644 --- a/source/slang/slang-ir-specialize.cpp +++ b/source/slang/slang-ir-specialize.cpp @@ -7,7 +7,6 @@ #include "slang-ir-ssa-simplification.h" #include "slang-ir-lower-witness-lookup.h" #include "slang-ir-dce.h" -#include "slang-ir-util.h" #include "../core/slang-performance-profiler.h" namespace Slang @@ -37,10 +36,10 @@ namespace Slang struct SpecializationContext; IRInst* specializeGenericImpl( - IRGeneric* genericVal, - IRSpecialize* specializeInst, - IRModule* module, - SpecializationContext* context); + IRGeneric* genericVal, + IRSpecialize* specializeInst, + IRModule* module, + SpecializationContext* context); struct SpecializationContext { @@ -58,29 +57,21 @@ struct SpecializationContext // specialized-ness of an instruction depends on the // fully-specialized-ness of its operands. // - // We will use an inst's scratchData to represent whether or not - // the inst is considered as fully specialized. + // We will build an explicit hash set to encode those + // instructions that are fully specialized. // - void setFullySpecializedBit(IRInst* inst) - { - inst->scratchData |= 1; - } - bool getFullySpecializedBit(IRInst* inst) - { - return (inst->scratchData & 1) != 0; - } - void setCleanBit(IRInst* inst) - { - inst->scratchData |= 2; - } - void resetCleanBit(IRInst* inst) - { - inst->scratchData &= (~2); - } - bool getCleanBit(IRInst* inst) + HashSet<IRInst*>& fullySpecializedInsts; + + SpecializationContext(IRModule* inModule) + : fullySpecializedInsts(*module->getContainerPool().getHashSet<IRInst>()) + , cleanInsts(*module->getContainerPool().getHashSet<IRInst>()) + , module(inModule) { - return (inst->scratchData & 2) != 0; } + + // An instruction is then fully specialized if and only + // if it is in our set. + // bool isInstFullySpecialized( IRInst* inst) { @@ -127,7 +118,7 @@ struct SpecializationContext } } - return getFullySpecializedBit(inst); + return fullySpecializedInsts.contains(inst); } // When an instruction isn't fully specialized, but its operands *are* @@ -135,16 +126,16 @@ struct SpecializationContext // a query to check for the "all operands fully specialized" case. // bool areAllOperandsFullySpecialized( - IRInst* inst) + IRInst* inst) { - if(!isInstFullySpecialized(inst->getFullType())) + if (!isInstFullySpecialized(inst->getFullType())) return false; UInt operandCount = inst->getOperandCount(); - for(UInt ii = 0; ii < operandCount; ++ii) + for (UInt ii = 0; ii < operandCount; ++ii) { IRInst* operand = inst->getOperand(ii); - if(!isInstFullySpecialized(operand)) + if (!isInstFullySpecialized(operand)) return false; } @@ -156,6 +147,7 @@ struct SpecializationContext // whether generic, existential, etc. // OrderedHashSet<IRInst*> workList; + HashSet<IRInst*>& cleanInsts; void addToWorkList( IRInst* inst) @@ -172,16 +164,16 @@ struct SpecializationContext // because it doesn't make sense to perform specialization // on such code. // - for( auto ii = inst->getParent(); ii; ii = ii->getParent() ) + for (auto ii = inst->getParent(); ii; ii = ii->getParent()) { - if(as<IRGeneric>(ii)) + if (as<IRGeneric>(ii)) return; } #endif if (workList.add(inst)) { - resetCleanBit(inst); + cleanInsts.remove(inst); addUsersToWorkList(inst); } @@ -195,10 +187,10 @@ struct SpecializationContext void addUsersToWorkList( IRInst* inst) { - for( auto use = inst->firstUse; use; use = use->nextUse ) + for (auto use = inst->firstUse; use; use = use->nextUse) { auto user = use->getUser(); - + addToWorkList(user); } } @@ -209,9 +201,9 @@ struct SpecializationContext void markInstAsFullySpecialized( IRInst* inst) { - if(getFullySpecializedBit(inst)) + if (fullySpecializedInsts.contains(inst)) return; - setFullySpecializedBit(inst); + fullySpecializedInsts.add(inst); // If we know that an instruction is fully specialized, // then we should start to consider its uses and children @@ -247,8 +239,8 @@ struct SpecializationContext // instruction. // IRInst* specializeGeneric( - IRGeneric* genericVal, - IRSpecialize* specializeInst) + IRGeneric* genericVal, + IRSpecialize* specializeInst) { // First, we want to see if an existing specialization // has already been made. To do that we will construct a key @@ -263,7 +255,7 @@ struct SpecializationContext Key key; key.vals.add(specializeInst->getBase()); UInt argCount = specializeInst->getArgCount(); - for( UInt ii = 0; ii < argCount; ++ii ) + for (UInt ii = 0; ii < argCount; ++ii) { key.vals.add(specializeInst->getArg(ii)); } @@ -274,7 +266,7 @@ struct SpecializationContext // If one is found, our work is done. // IRInst* specializedVal = nullptr; - if(genericSpecializations.tryGetValue(key, specializedVal)) + if (genericSpecializations.tryGetValue(key, specializedVal)) return specializedVal; } @@ -318,7 +310,7 @@ struct SpecializationContext // by looking at whether it is a definition or a declaration. // bool canSpecializeGeneric( - IRGeneric* generic) + IRGeneric* generic) { // It is possible to have multiple "layers" of generics // (e.g., when a generic function is nested in a generic @@ -327,20 +319,20 @@ struct SpecializationContext // something that looks like a definition. // IRGeneric* g = generic; - for(;;) + for (;;) { // We can't specialize a generic if it is marked as // being imported from an external module (in which // case its definition is not available to us). // - if(!isDefinition(g)) + if (!isDefinition(g)) return false; // Given the generic `g`, we will find the value // it appears to return in its body. // auto val = findGenericReturnVal(g); - if(!val) + if (!val) return false; // If `g` returns an inner generic, then we need @@ -361,7 +353,7 @@ struct SpecializationContext // by having the linking step strip/skip decorations // that aren't applicable to the chosen target at link time. // - if(as<IRStructType>(val) && val->findDecoration<IRTargetIntrinsicDecoration>()) + if (as<IRStructType>(val) && val->findDecoration<IRTargetIntrinsicDecoration>()) return false; // Once we've found the leaf value that will be produced @@ -384,7 +376,7 @@ struct SpecializationContext // operands to the `speicalize(...)` instruction are // themselves fully specialized. // - if(!areAllOperandsFullySpecialized(specInst)) + if (!areAllOperandsFullySpecialized(specInst)) return false; // The invariant that the arguments are fully specialized @@ -397,13 +389,13 @@ struct SpecializationContext // auto baseVal = specInst->getBase(); auto genericVal = as<IRGeneric>(baseVal); - if(!genericVal) + if (!genericVal) return false; // We can also only specialize a generic if it // represents a definition rather than a declaration. // - if(!canSpecializeGeneric(genericVal)) + if (!canSpecializeGeneric(genericVal)) { // We have to consider a special case here if baseVal is // an intrinsic, and contains a custom differential. @@ -530,7 +522,7 @@ struct SpecializationContext // since values are an important class of instruction we want // to deduplicate. - switch(inst->getOp()) + switch (inst->getOp()) { default: // The default case is that an instruction can @@ -566,37 +558,37 @@ struct SpecializationContext // case where this code path first showed up // as necessary was `RayQuery<>`) // + { + auto specialize = cast<IRSpecialize>(inst); + auto base = specialize->getBase(); + if (auto generic = as<IRGeneric>(base)) { - auto specialize = cast<IRSpecialize>(inst); - auto base = specialize->getBase(); - if( auto generic = as<IRGeneric>(base) ) + // If the thing being specialized can be resolved, + // *and* it is a target intrinsic, ... + // + if (auto result = findGenericReturnVal(generic)) { - // If the thing being specialized can be resolved, - // *and* it is a target intrinsic, ... - // - if( auto result = findGenericReturnVal(generic) ) + if (result->findDecoration<IRTargetIntrinsicDecoration>()) { - if( result->findDecoration<IRTargetIntrinsicDecoration>() ) + // ... then we should consider the instruction as + // "fully specialized" in the same cases as for + // any ordinary instruciton. + // + + if (areAllOperandsFullySpecialized(inst)) { - // ... then we should consider the instruction as - // "fully specialized" in the same cases as for - // any ordinary instruciton. - // - - if( areAllOperandsFullySpecialized(inst) ) - { - markInstAsFullySpecialized(inst); - } - return; + markInstAsFullySpecialized(inst); } + return; } } - - // Otherwise, a `specialize` instruction falls into - // the case of instructions that should never be - // considered to be fully specialized. } - break; + + // Otherwise, a `specialize` instruction falls into + // the case of instructions that should never be + // considered to be fully specialized. + } + break; } } @@ -605,9 +597,9 @@ struct SpecializationContext // is appropriate based on its opcode. // bool maybeSpecializeInst( - IRInst* inst) + IRInst* inst) { - switch(inst->getOp()) + switch (inst->getOp()) { default: // By default we assume that specialization is @@ -688,7 +680,7 @@ struct SpecializationContext // operation that will yield such a table. // auto witnessTable = as<IRWitnessTable>(lookupInst->getWitnessTable()); - if(!witnessTable) + if (!witnessTable) return false; // Because we have a concrete witness table, we can @@ -703,7 +695,7 @@ struct SpecializationContext // we leave "correct" but unspecialized code if // we cannot find a concrete value to use. // - if(!satisfyingVal) + if (!satisfyingVal) return false; // At this point, we know that `satisfyingVal` is what @@ -729,13 +721,13 @@ struct SpecializationContext // IRInst* findWitnessVal( IRWitnessTable* witnessTable, - IRInst* requirementKey) + IRInst* requirementKey) { // A witness table is basically just a container // for key-value pairs, and so the best we can // do for now is a naive linear search. // - for( auto entry : witnessTable->getEntries() ) + for (auto entry : witnessTable->getEntries()) { if (requirementKey == entry->getRequirementKey()) { @@ -889,9 +881,6 @@ struct SpecializationContext for (;;) { bool iterChanged = false; - - initializeScratchData(module->getModuleInst()); - addToWorkList(module->getModuleInst()); while (workList.getCount() != 0) @@ -904,7 +893,7 @@ struct SpecializationContext workList.removeLast(); - setCleanBit(inst); + cleanInsts.add(inst); // For each instruction we process, we want to perform // a few steps. @@ -977,12 +966,12 @@ struct SpecializationContext void addDirtyInstsToWorkListRec(IRInst* inst) { - if( !getCleanBit(inst) ) + if (!cleanInsts.contains(inst)) { addToWorkList(inst); } - for(auto child = inst->getLastChild(); child; child = child->getPrevInst()) + for (auto child = inst->getLastChild(); child; child = child->getPrevInst()) { addDirtyInstsToWorkListRec(child); } @@ -1042,7 +1031,7 @@ struct SpecializationContext if (auto wrapExistential = as<IRWrapExistential>(inst->getArg(0))) { if (auto sbType = as<IRHLSLStructuredBufferTypeBase>( - wrapExistential->getWrappedValue()->getDataType())) + wrapExistential->getWrappedValue()->getDataType())) { // We are seeing the instruction sequence in the form of // .operator[](wrapExistential(structuredBuffer), idx). @@ -1110,7 +1099,7 @@ struct SpecializationContext // We can only specialize a call when the callee function is known. // auto calleeFunc = as<IRFunc>(inst->getCallee()); - if(!calleeFunc) + if (!calleeFunc) return false; // Update result type since the callee may have been changed. @@ -1121,7 +1110,7 @@ struct SpecializationContext // We can only specialize if we have access to a body for the callee. // - if(!calleeFunc->isDefinition()) + if (!calleeFunc->isDefinition()) return false; // We shouldn't bother specializing unless the callee has at least @@ -1129,10 +1118,10 @@ struct SpecializationContext // bool shouldSpecialize = false; UInt argCounter = 0; - for( auto param : calleeFunc->getParams() ) + for (auto param : calleeFunc->getParams()) { auto arg = inst->getArg(argCounter++); - if( !isExistentialType(param->getDataType()) ) + if (!isExistentialType(param->getDataType())) continue; shouldSpecialize = true; @@ -1140,13 +1129,13 @@ struct SpecializationContext // We *cannot* specialize unless the argument value corresponding // to such a parameter is one we can specialize. // - if( !canSpecializeExistentialArg(arg)) + if (!canSpecializeExistentialArg(arg)) return false; } // If we never found a parameter worth specializing, we should bail out. // - if(!shouldSpecialize) + if (!shouldSpecialize) return false; // At this point, we believe we *should* and *can* specialize. @@ -1173,13 +1162,13 @@ struct SpecializationContext // argument. // argCounter = 0; - for( auto param : calleeFunc->getParams() ) + for (auto param : calleeFunc->getParams()) { auto arg = inst->getArg(argCounter++); - if( !isExistentialType(param->getDataType()) ) + if (!isExistentialType(param->getDataType())) continue; - if( auto makeExistential = as<IRMakeExistential>(arg) ) + if (auto makeExistential = as<IRMakeExistential>(arg)) { // Note that we use the *type* stored in the // existential-type argument, but not anything to @@ -1208,14 +1197,14 @@ struct SpecializationContext auto witnessTable = makeExistential->getWitnessTable(); key.vals.add(witnessTable); } - else if( auto wrapExistential = as<IRWrapExistential>(arg) ) + else if (auto wrapExistential = as<IRWrapExistential>(arg)) { auto val = wrapExistential->getWrappedValue(); auto valType = val->getFullType(); key.vals.add(valType); UInt slotOperandCount = wrapExistential->getSlotOperandCount(); - for( UInt ii = 0; ii < slotOperandCount; ++ii ) + for (UInt ii = 0; ii < slotOperandCount; ++ii) { auto slotOperand = wrapExistential->getSlotOperand(ii); key.vals.add(slotOperand); @@ -1231,7 +1220,7 @@ struct SpecializationContext // existing specialization of the callee that we can use. // IRFunc* specializedCallee = nullptr; - if( !existentialSpecializedFuncs.tryGetValue(key, specializedCallee) ) + if (!existentialSpecializedFuncs.tryGetValue(key, specializedCallee)) { // If we didn't find a specialized callee already made, then we // will go ahead and create one, and then register it in our cache. @@ -1247,14 +1236,14 @@ struct SpecializationContext // argCounter = 0; List<IRInst*> newArgs; - for( auto param : calleeFunc->getParams() ) + for (auto param : calleeFunc->getParams()) { auto arg = inst->getArg(argCounter++); // How we handle each argument depends on whether the corresponding // parameter has an existential type or not. // - if( !isExistentialType(param->getDataType()) ) + if (!isExistentialType(param->getDataType())) { // If the parameter doesn't have an existential type, then we // don't want to change up the argument we pass at all. @@ -1267,12 +1256,12 @@ struct SpecializationContext // existential type, we will now be passing in the concrete // argument value instead of an existential wrapper. // - if( auto makeExistential = as<IRMakeExistential>(arg) ) + if (auto makeExistential = as<IRMakeExistential>(arg)) { auto val = makeExistential->getWrappedValue(); newArgs.add(val); } - else if( auto wrapExistential = as<IRWrapExistential>(arg) ) + else if (auto wrapExistential = as<IRWrapExistential>(arg)) { auto val = wrapExistential->getWrappedValue(); newArgs.add(val); @@ -1322,7 +1311,7 @@ struct SpecializationContext { // An IR-level interface type is always an existential. // - if(as<IRInterfaceType>(type)) + if (as<IRInterfaceType>(type)) return true; if (calcExistentialTypeParamSlotCount(type) != 0) return true; @@ -1339,8 +1328,8 @@ struct SpecializationContext // TODO: We probably need/want a more robust test here. // For now we are just look into the dependency graph of the inst and // see if there are any opcodes that are causing problems. - InstWorkList localWorkList(inst->getModule()); - InstHashSet processedInsts(inst->getModule()); + List<IRInst*> localWorkList; + HashSet<IRInst*> processedInsts; localWorkList.add(inst); processedInsts.add(inst); @@ -1385,7 +1374,7 @@ struct SpecializationContext // (which implicitly determines the concrete type), and // the witness table `w. // - if( auto makeExistential = as<IRMakeExistential>(inst) ) + if (auto makeExistential = as<IRMakeExistential>(inst)) { // We need to be careful about the type that we'd be specializing // to, since it needs to be visible to both the caller and calee. @@ -1406,7 +1395,7 @@ struct SpecializationContext // is just a generalization of `makeExistential`, so it // can apply in the same cases. // - if(as<IRWrapExistential>(inst)) + if (as<IRWrapExistential>(inst)) return true; // If we start to specialize functions that take arrays @@ -1463,7 +1452,7 @@ struct SpecializationContext List<IRParam*> newParams; List<IRInst*> newBodyInsts; UInt argCounter = 0; - for( auto oldParam : oldFunc->getParams() ) + for (auto oldParam : oldFunc->getParams()) { auto arg = oldCall->getArg(argCounter++); @@ -1478,7 +1467,7 @@ struct SpecializationContext // parameter, because we need to extract out the concrete // type that is coming from the call site. // - if( auto oldMakeExistential = as<IRMakeExistential>(arg) ) + if (auto oldMakeExistential = as<IRMakeExistential>(arg)) { // In this case, the `arg` is `makeExistential(val, witnessTable)` // and we know that the specialized call site will just be @@ -1508,7 +1497,7 @@ struct SpecializationContext newBodyInsts.add(newMakeExistential); replacementVal = newMakeExistential; } - else if( auto oldWrapExistential = as<IRWrapExistential>(arg) ) + else if (auto oldWrapExistential = as<IRWrapExistential>(arg)) { auto val = oldWrapExistential->getWrappedValue(); auto valType = val->getFullType(); @@ -1558,7 +1547,7 @@ struct SpecializationContext // need to extract the types of all its parameters. // List<IRType*> newParamTypes; - for( auto newParam : newParams ) + for (auto newParam : newParams) { newParamTypes.add(newParam->getFullType()); } @@ -1573,7 +1562,7 @@ struct SpecializationContext // "fully specialized" by the rules used for doing // generic specialization elsewhere in this pass. // - setFullySpecializedBit(newFuncType); + fullySpecializedInsts.add(newFuncType); // The above steps have accomplished the "first phase" // of cloning the function (since `IRFunc`s have no @@ -1612,7 +1601,7 @@ struct SpecializationContext // the first ordinary instruction (since the function parameters // should come at the start of the first block). // - for( auto newParam : newParams ) + for (auto newParam : newParams) { newParam->insertBefore(newFirstOrdinary); } @@ -1621,7 +1610,7 @@ struct SpecializationContext // before the first ordinary instruction (but will come // *after* the parameters by the order of these two loops). // - for( auto newBodyInst : newBodyInsts ) + for (auto newBodyInst : newBodyInsts) { newBodyInst->insertBefore(newFirstOrdinary); } @@ -1670,7 +1659,7 @@ struct SpecializationContext // auto existentialArg = inst->getOperand(0); - if( auto makeExistential = as<IRMakeExistential>(existentialArg) ) + if (auto makeExistential = as<IRMakeExistential>(existentialArg)) { // In this case we know `inst` is: // @@ -1702,7 +1691,7 @@ struct SpecializationContext // We know `inst` is `extractExistentialValue(existentialArg)`. // auto existentialArg = inst->getOperand(0); - if( auto makeExistential = as<IRMakeExistential>(existentialArg) ) + if (auto makeExistential = as<IRMakeExistential>(existentialArg)) { // Now we know `inst` is: // @@ -1729,7 +1718,7 @@ struct SpecializationContext // We know `inst` is `extractExistentialValue(existentialArg)`. // auto existentialArg = inst->getOperand(0); - if( auto makeExistential = as<IRMakeExistential>(existentialArg) ) + if (auto makeExistential = as<IRMakeExistential>(existentialArg)) { // Now we know `inst` is: // @@ -1753,7 +1742,7 @@ struct SpecializationContext { auto ptrArg = inst->ptr.get(); - if( auto wrapInst = as<IRWrapExistential>(ptrArg) ) + if (auto wrapInst = as<IRWrapExistential>(ptrArg)) { // We have an instruction of the form `load(wrapExistential(val, ...))` // @@ -1777,13 +1766,13 @@ struct SpecializationContext // the type that `load(val)` should return. // auto elementType = tryGetPointedToType(&builder, val->getDataType()); - if(!elementType) + if (!elementType) return false; List<IRInst*> slotOperands; UInt slotOperandCount = wrapInst->getSlotOperandCount(); - for( UInt ii = 0; ii < slotOperandCount; ++ii ) + for (UInt ii = 0; ii < slotOperandCount; ++ii) { slotOperands.add(wrapInst->getSlotOperand(ii)); } @@ -1807,20 +1796,20 @@ struct SpecializationContext UInt calcExistentialBoxSlotCount(IRType* type) { top: - if( as<IRBoundInterfaceType>(type) ) + if (as<IRBoundInterfaceType>(type)) { return 2; } - else if( as<IRInterfaceType>(type) ) + else if (as<IRInterfaceType>(type)) { return 2; } - else if( auto ptrType = as<IRPtrTypeBase>(type) ) + else if (auto ptrType = as<IRPtrTypeBase>(type)) { type = ptrType->getValueType(); goto top; } - else if( auto ptrLikeType = as<IRPointerLikeType>(type) ) + else if (auto ptrLikeType = as<IRPointerLikeType>(type)) { type = ptrLikeType->getElementType(); goto top; @@ -1840,10 +1829,10 @@ struct SpecializationContext type = attributedType->getBaseType(); goto top; } - else if( auto structType = as<IRStructType>(type) ) + else if (auto structType = as<IRStructType>(type)) { UInt count = 0; - for( auto field : structType->getFields() ) + for (auto field : structType->getFields()) { count += calcExistentialBoxSlotCount(field->getFieldType()); } @@ -1860,7 +1849,7 @@ struct SpecializationContext auto baseArg = inst->getBase(); auto fieldKey = inst->getField(); - if( auto wrapInst = as<IRWrapExistential>(baseArg) ) + if (auto wrapInst = as<IRWrapExistential>(baseArg)) { // We have `getField(wrapExistential(val, ...), fieldKey)` // @@ -1892,15 +1881,15 @@ struct SpecializationContext // auto valType = val->getDataType(); auto valStructType = as<IRStructType>(valType); - if(!valStructType) + if (!valStructType) return false; UInt slotOperandOffset = 0; IRStructField* foundField = nullptr; - for( auto valField : valStructType->getFields() ) + for (auto valField : valStructType->getFields()) { - if( valField->getKey() == fieldKey ) + if (valField->getKey() == fieldKey) { foundField = valField; break; @@ -1909,7 +1898,7 @@ struct SpecializationContext slotOperandOffset += calcExistentialBoxSlotCount(valField->getFieldType()); } - if(!foundField) + if (!foundField) return false; auto foundFieldType = foundField->getFieldType(); @@ -1917,7 +1906,7 @@ struct SpecializationContext List<IRInst*> slotOperands; UInt slotOperandCount = calcExistentialBoxSlotCount(foundFieldType); - for( UInt ii = 0; ii < slotOperandCount; ++ii ) + for (UInt ii = 0; ii < slotOperandCount; ++ii) { slotOperands.add(wrapInst->getSlotOperand(slotOperandOffset + ii)); } @@ -1947,7 +1936,7 @@ struct SpecializationContext auto baseArg = inst->getBase(); auto fieldKey = inst->getField(); - if( auto wrapInst = as<IRWrapExistential>(baseArg) ) + if (auto wrapInst = as<IRWrapExistential>(baseArg)) { // We have `getFieldAddr(wrapExistential(val, ...), fieldKey)` // @@ -1978,19 +1967,19 @@ struct SpecializationContext // up the field corresponding to `fieldKey`. // auto valType = tryGetPointedToType(&builder, val->getDataType()); - if(!valType) + if (!valType) return false; auto valStructType = as<IRStructType>(valType); - if(!valStructType) + if (!valStructType) return false; UInt slotOperandOffset = 0; IRStructField* foundField = nullptr; - for( auto valField : valStructType->getFields() ) + for (auto valField : valStructType->getFields()) { - if( valField->getKey() == fieldKey ) + if (valField->getKey() == fieldKey) { foundField = valField; break; @@ -1999,7 +1988,7 @@ struct SpecializationContext slotOperandOffset += calcExistentialBoxSlotCount(valField->getFieldType()); } - if(!foundField) + if (!foundField) return false; auto foundFieldType = foundField->getFieldType(); @@ -2007,7 +1996,7 @@ struct SpecializationContext List<IRInst*> slotOperands; UInt slotOperandCount = calcExistentialBoxSlotCount(foundFieldType); - for( UInt ii = 0; ii < slotOperandCount; ++ii ) + for (UInt ii = 0; ii < slotOperandCount; ++ii) { slotOperands.add(wrapInst->getSlotOperand(slotOperandOffset + ii)); } @@ -2115,16 +2104,16 @@ struct SpecializationContext UInt calcExistentialTypeParamSlotCount(IRType* type) { top: - if( as<IRInterfaceType>(type) ) + if (as<IRInterfaceType>(type)) { return 2; } - else if( auto ptrType = as<IRPtrTypeBase>(type) ) + else if (auto ptrType = as<IRPtrTypeBase>(type)) { type = ptrType->getValueType(); goto top; } - else if( auto ptrLikeType = as<IRPointerLikeType>(type) ) + else if (auto ptrLikeType = as<IRPointerLikeType>(type)) { type = ptrLikeType->getElementType(); goto top; @@ -2139,10 +2128,10 @@ struct SpecializationContext type = attributedType->getBaseType(); goto top; } - else if( auto structType = as<IRStructType>(type) ) + else if (auto structType = as<IRStructType>(type)) { UInt count = 0; - for( auto field : structType->getFields() ) + for (auto field : structType->getFields()) { count += calcExistentialTypeParamSlotCount(field->getFieldType()); } @@ -2164,15 +2153,15 @@ struct SpecializationContext IRBuilder builder(module); builder.setInsertBefore(type); - if( auto baseInterfaceType = as<IRInterfaceType>(baseType) ) + if (auto baseInterfaceType = as<IRInterfaceType>(baseType)) { // We always expect two slot operands, one for the concrete type // and one for the witness table. // SLANG_ASSERT(slotOperandCount == 2); - if(slotOperandCount < 2) return false; + if (slotOperandCount < 2) return false; - auto concreteType = (IRType*) type->getExistentialArg(0); + auto concreteType = (IRType*)type->getExistentialArg(0); auto witnessTable = type->getExistentialArg(1); auto newVal = builder.getBoundInterfaceType(baseInterfaceType, concreteType, witnessTable); @@ -2181,10 +2170,10 @@ struct SpecializationContext type->removeAndDeallocate(); return true; } - else if( as<IRPointerLikeType>(baseType) || - as<IRHLSLStructuredBufferTypeBase>(baseType) || - as<IRArrayTypeBase>(baseType) || - as<IRAttributedType>(baseType) ) + else if (as<IRPointerLikeType>(baseType) || + as<IRHLSLStructuredBufferTypeBase>(baseType) || + as<IRArrayTypeBase>(baseType) || + as<IRAttributedType>(baseType)) { // A `BindExistentials<P<T>, ...>` can be simplified to // `P<BindExistentials<T, ...>>` when `P` is a pointer-like @@ -2217,7 +2206,7 @@ struct SpecializationContext type->removeAndDeallocate(); return true; } - else if( auto baseStructType = as<IRStructType>(baseType) ) + else if (auto baseStructType = as<IRStructType>(baseType)) { // In order to bind a `struct` type we will generate // a new specialized `struct` type on demand and then @@ -2229,7 +2218,7 @@ struct SpecializationContext // specialized, so that we can be sure that we // have a unique type. // - if( !areAllOperandsFullySpecialized(type) ) + if (!areAllOperandsFullySpecialized(type)) return false; // Now we we check to see if we've already created @@ -2237,7 +2226,7 @@ struct SpecializationContext // IRSimpleSpecializationKey key; key.vals.add(baseStructType); - for( UInt ii = 0; ii < slotOperandCount; ++ii ) + for (UInt ii = 0; ii < slotOperandCount; ++ii) { key.vals.add(type->getExistentialArg(ii)); } @@ -2245,7 +2234,7 @@ struct SpecializationContext IRStructType* newStructType = nullptr; addUsersToWorkList(type); - if( !existentialSpecializedStructs.tryGetValue(key, newStructType) ) + if (!existentialSpecializedStructs.tryGetValue(key, newStructType)) { builder.setInsertBefore(baseStructType); newStructType = builder.createStructType(); @@ -2253,7 +2242,7 @@ struct SpecializationContext auto fieldSlotArgs = type->getExistentialArgs(); - for( auto oldField : baseStructType->getFields() ) + for (auto oldField : baseStructType->getFields()) { // TODO: we need to figure out which of the specialization arguments // apply to this field... @@ -2291,13 +2280,13 @@ struct SpecializationContext void specializeGlobalGenericParameters() { auto moduleInst = module->getModuleInst(); - for(auto inst : moduleInst->getChildren()) + for (auto inst : moduleInst->getChildren()) { // We only want to consider the `bind_global_generic_param` // instructions, and ignore everything else. // auto bindInst = as<IRBindGlobalGenericParam>(inst); - if(!bindInst) + if (!bindInst) continue; // HACK: Our current front-end emit logic can end up emitting multiple @@ -2308,7 +2297,7 @@ struct SpecializationContext // For now we will do a sanity check to detect parameters that // have already been specialized. // - if( !as<IRGlobalGenericParam>(bindInst->getOperand(0)) ) + if (!as<IRGlobalGenericParam>(bindInst->getOperand(0))) { // The "parameter" operand is no longer a parameter, so it // seems things must have been specialized already. @@ -2331,11 +2320,11 @@ struct SpecializationContext // instructions, since both should be dead/unused. // IRInst* next = nullptr; - for(auto inst = moduleInst->getFirstChild(); inst; inst = next) + for (auto inst = moduleInst->getFirstChild(); inst; inst = next) { next = inst->getNextInst(); - switch(inst->getOp()) + switch (inst->getOp()) { default: break; @@ -2356,12 +2345,11 @@ struct SpecializationContext }; bool specializeModule( - IRModule* module, + IRModule* module, DiagnosticSink* sink) { SLANG_PROFILE; - SpecializationContext context; - context.module = module; + SpecializationContext context(module); context.sink = sink; context.processModule(); return context.changed; @@ -2375,11 +2363,11 @@ void finalizeSpecialization(IRModule* module) auto moduleInst = module->getModuleInst(); IRInst* next = nullptr; - for(auto inst = moduleInst->getFirstChild(); inst; inst = next) + for (auto inst = moduleInst->getFirstChild(); inst; inst = next) { next = inst->getNextInst(); - switch(inst->getOp()) + switch (inst->getOp()) { default: break; @@ -2410,10 +2398,10 @@ void finalizeSpecialization(IRModule* module) } IRInst* specializeGenericImpl( - IRGeneric* genericVal, - IRSpecialize* specializeInst, - IRModule* module, - SpecializationContext* context) + IRGeneric* genericVal, + IRSpecialize* specializeInst, + IRModule* module, + SpecializationContext* context) { // Effectively, specializing a generic amounts to "calling" the generic // on its concrete argument values and computing the @@ -2440,7 +2428,7 @@ IRInst* specializeGenericImpl( // and `V -> c`. // UInt argCounter = 0; - for( auto param : genericVal->getParams() ) + for (auto param : genericVal->getParams()) { UInt argIndex = argCounter++; SLANG_ASSERT(argIndex < specializeInst->getArgCount()); @@ -2462,7 +2450,7 @@ IRInst* specializeGenericImpl( // clone each of its instructions into the global scope, // until we reach a `return` instruction. // - for( auto bb : genericVal->getBlocks() ) + for (auto bb : genericVal->getBlocks()) { // We expect a generic to only ever contain a single block. // @@ -2472,7 +2460,7 @@ IRInst* specializeGenericImpl( // instructions only, because parameters were dealt // with explictly at an earlier point. // - for( auto ii : bb->getOrdinaryInsts() ) + for (auto ii : bb->getOrdinaryInsts()) { // The last block of the generic is expected to end with // a `return` instruction for the specialized value that @@ -2481,7 +2469,7 @@ IRInst* specializeGenericImpl( // We thus use that cloned value as the result of the // specialization step. // - if( auto returnValInst = as<IRReturn>(ii) ) + if (auto returnValInst = as<IRReturn>(ii)) { auto specializedVal = findCloneForOperand(&env, returnValInst->getVal()); @@ -2516,7 +2504,7 @@ IRInst* specializeGenericImpl( // operations nested inside the first generic that refer // to the second. // - if( context ) + if (context) { context->addToWorkList(clonedInst); } @@ -2531,15 +2519,15 @@ IRInst* specializeGenericImpl( } IRInst* specializeGeneric( - IRSpecialize* specializeInst) + IRSpecialize* specializeInst) { auto baseGeneric = as<IRGeneric>(specializeInst->getBase()); SLANG_ASSERT(baseGeneric); - if(!baseGeneric) return specializeInst; + if (!baseGeneric) return specializeInst; auto module = specializeInst->getModule(); SLANG_ASSERT(module); - if(!module) return specializeInst; + if (!module) return specializeInst; return specializeGenericImpl(baseGeneric, specializeInst, module, nullptr); } diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h index 98c3996a2..983c39218 100644 --- a/source/slang/slang-ir-util.h +++ b/source/slang/slang-ir-util.h @@ -53,9 +53,6 @@ struct DeduplicateContext if (deduplicatedOperand != value->getOperand(i)) value->unsafeSetOperand(i, deduplicatedOperand); } - auto deduplicatedType = (IRType*)deduplicate(value->getFullType(), shouldDeduplicate); - if (deduplicatedType != value->getFullType()) - value->setFullType(deduplicatedType); if (auto newValue = deduplicateMap.tryGetValue(key)) return *newValue; deduplicateMap[key] = value; diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 35803cedb..b6c19b18d 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -6849,6 +6849,8 @@ namespace Slang thisInst = workItem.thisInst; other = workItem.otherInst; + SLANG_ASSERT(other); + // Safety check: don't try to replace something with itself. if (other == thisInst) continue; @@ -6902,6 +6904,8 @@ namespace Slang IRInst* existingVal = nullptr; if (dedupContext->getGlobalValueNumberingMap().tryGetValue(IRInstKey{ user }, existingVal)) { + // If existingVal has been replaced by something else, use that. + dedupContext->getInstReplacementMap().tryGetValue(existingVal, existingVal); addToWorkList(user, existingVal); } else diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index e61ed99af..2edda0f4f 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -703,6 +703,12 @@ struct IRInst uint32_t _debugUID; #endif + // Reserved memory space for use by individual IR passes. + // This field is not supposed to be valid outside an IR pass, + // and each IR pass should always treat it as uninitialized + // upon entry. + UInt64 scratchData = 0; + // The type of the result value of this instruction, // or `null` to indicate that the instruction has // no value. @@ -740,12 +746,6 @@ struct IRInst getOperands()[index].init(this, value); } - // Reserved memory space for use by individual IR passes. - // This field is not supposed to be valid outside an IR pass, - // and each IR pass should always treat it as uninitialized - // upon entry. - UInt64 scratchData = 0; - // // Replace all uses of this value with `other`, so diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index efc413e24..2eca91673 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -200,7 +200,7 @@ static void _lookUpDirectAndTransparentMembers( // Skip this declaration if we are checking and this hasn't been // checked yet. Because we traverse block statements in order, if // it's unchecked or being checked then it isn't declared yet. - if(!request.shouldConsiderAllLocalNames() && _isUncheckedLocalVar(m)) + if(!request.shouldConsiderAllLocalNames() && request.semantics && _isUncheckedLocalVar(m)) continue; if (!DeclPassesLookupMask(m, request.mask)) @@ -300,17 +300,28 @@ static SubtypeWitness* _makeSubtypeWitness( } } -static SubtypeWitness* _makeSubtypeWitness( - ASTBuilder* astBuilder, - Type* subType, - SubtypeWitness* subToMidWitness, - Type* superType, - DeclRef<TypeConstraintDecl> midToSuperConstraint) +// Specialize `declRefToSpecialize` with ThisType info if `superType` is an interface type. +DeclRef<Decl> _maybeSpecializeSuperTypeDeclRef( + ASTBuilder* astBuilder, + DeclRef<Decl> declRefToSpecialize, + Type* superType, + SubtypeWitness* subIsSuperWitness) { - auto midToSuperWitness = astBuilder->getDeclaredSubtypeWitness( - subType, superType, midToSuperConstraint); - return _makeSubtypeWitness( - astBuilder, subType, subToMidWitness, superType, midToSuperWitness); + if (auto superDeclRefType = as<DeclRefType>(superType)) + { + if (auto superInterfaceDeclRef = superDeclRefType->declRef.as<InterfaceDecl>()) + { + ThisTypeSubstitution* thisTypeSubst = astBuilder->getOrCreateThisTypeSubstitution( + superInterfaceDeclRef.getDecl(), + subIsSuperWitness, + declRefToSpecialize.getSubst()); + + auto specializedDeclRef = astBuilder->getSpecializedDeclRef<Decl>(declRefToSpecialize.getDecl(), thisTypeSubst); + + return specializedDeclRef; + } + } + return declRefToSpecialize; } // Same as the above, but we are specializing a type instead of a decl-ref @@ -321,18 +332,8 @@ static Type* _maybeSpecializeSuperType( { if (auto superDeclRefType = as<DeclRefType>(superType)) { - if (auto superInterfaceDeclRef = superDeclRefType->declRef.as<InterfaceDecl>()) - { - ThisTypeSubstitution* thisTypeSubst = astBuilder->create<ThisTypeSubstitution>(); - thisTypeSubst->interfaceDecl = superInterfaceDeclRef.getDecl(); - thisTypeSubst->witness = subIsSuperWitness; - thisTypeSubst->outer = superInterfaceDeclRef.getSubst(); - - auto specializedInterfaceDeclRef = astBuilder->getSpecializedDeclRef<Decl>(superInterfaceDeclRef.getDecl(), thisTypeSubst); - - auto specializedInterfaceType = DeclRefType::create(astBuilder, specializedInterfaceDeclRef); - return specializedInterfaceType; - } + auto specializedDeclRef = _maybeSpecializeSuperTypeDeclRef(astBuilder, superDeclRefType->declRef, superType, subIsSuperWitness); + return DeclRefType::create(astBuilder, specializedDeclRef); } return superType; @@ -389,189 +390,119 @@ static void _lookUpMembersInSuperType( _lookUpMembersInSuperTypeImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, request, ioResult, &breadcrumb); } -static void _lookUpMembersInSuperType( - ASTBuilder* astBuilder, - Name* name, - Type* leafType, - SubtypeWitness* leafIsIntermediateWitness, - DeclRef<TypeConstraintDecl> intermediateIsSuperConstraint, - LookupRequest const& request, - LookupResult& ioResult, - BreadcrumbInfo* inBreadcrumbs) -{ - if( request.semantics ) - { - ensureDecl(request.semantics, intermediateIsSuperConstraint.getDecl(), DeclCheckState::CanUseBaseOfInheritanceDecl); - } - - // The super-type in the constraint (e.g., `Foo` in `T : Foo`) - // will tell us a type we should use for lookup. - // - auto superType = getSup(astBuilder, intermediateIsSuperConstraint); - // - // We will go ahead and perform lookup using `superType`, - // after dealing with some details. - - auto leafIsSuperWitness = _makeSubtypeWitness( - astBuilder, - leafType, - leafIsIntermediateWitness, - superType, - intermediateIsSuperConstraint); - - return _lookUpMembersInSuperType(astBuilder, name, leafType, superType, leafIsSuperWitness, request, ioResult, inBreadcrumbs); -} - static void _lookUpMembersInSuperTypeDeclImpl( ASTBuilder* astBuilder, Name* name, - Type* leafType, - Type* superType, - SubtypeWitness* leafIsSuperWitness, DeclRef<Decl> declRef, LookupRequest const& request, LookupResult& ioResult, BreadcrumbInfo* inBreadcrumbs) { auto semantics = request.semantics; - if( semantics ) - { - ensureDecl(semantics, declRef.getDecl(), DeclCheckState::ReadyForLookup); - } - if (auto genericTypeParamDeclRef = declRef.as<GenericTypeParamDecl>()) + // If the semantics context hasn't been established yet (e.g. when looking up during parsing), + // we simply do a direct lookup without considering subtypes or extensions. + // + if (!semantics) { - // If the type we are doing lookup in is a generic type parameter, - // then the members it provides can only be discovered by looking - // at the constraints that are placed on that type. - - auto genericDeclRef = genericTypeParamDeclRef.getParent(astBuilder).as<GenericDecl>(); - assert(genericDeclRef); - - for(auto constraintDeclRef : getMembersOfType<GenericTypeConstraintDecl>(astBuilder, DeclRef<ContainerDecl>(genericDeclRef))) + // In this case we can only lookup in an aggregate type. + if (auto aggTypeDeclBaseRef = declRef.as<AggTypeDeclBase>()) { - if( semantics ) - { - ensureDecl(semantics, constraintDeclRef.getDecl(), DeclCheckState::CanUseBaseOfInheritanceDecl); - } + _lookUpDirectAndTransparentMembers(astBuilder, name, aggTypeDeclBaseRef, request, ioResult, inBreadcrumbs); + } + return; + } - // Does this constraint pertain to the type we are working on? - // - // We want constraints of the form `T : Foo` where `T` is the - // generic parameter in question, and `Foo` is whatever we are - // constraining it to. - auto subType = getSub(astBuilder, constraintDeclRef); - auto subDeclRefType = as<DeclRefType>(subType); - if(!subDeclRefType) - continue; - if(!subDeclRefType->declRef.equals(genericTypeParamDeclRef)) - continue; + ensureDecl(semantics, declRef.getDecl(), DeclCheckState::ReadyForLookup); - _lookUpMembersInSuperType( - astBuilder, - name, - leafType, - leafIsSuperWitness, - constraintDeclRef, - request, - ioResult, - inBreadcrumbs); - } + // With semantics context, we can do a comprehensive lookup by scanning through + // the linearized inheritance list. + + InheritanceInfo inheritanceInfo; + if (auto extDeclRef = declRef.as<ExtensionDecl>()) + { + inheritanceInfo = semantics->getShared()->getInheritanceInfo(extDeclRef); } - else if (declRef.as<AssocTypeDecl>() || declRef.as<GlobalGenericParamDecl>()) + else { - for (auto constraintDeclRef : getMembersOfType<TypeConstraintDecl>(astBuilder, declRef.as<ContainerDecl>())) - { - _lookUpMembersInSuperType( - astBuilder, - name, - leafType, - leafIsSuperWitness, - constraintDeclRef, - request, - ioResult, - inBreadcrumbs); - } + auto selfType = DeclRefType::create(astBuilder, declRef); + inheritanceInfo = semantics->getShared()->getInheritanceInfo(selfType); } - else if(auto aggTypeDeclBaseRef = declRef.as<AggTypeDeclBase>()) + + for (auto facet : inheritanceInfo.facets) { - // In this case we are peforming lookup in the context of an aggregate - // type or an `extension`, so the first thing to do is to look for - // matching members declared directly in the body of the type/`extension`. - // - _lookUpDirectAndTransparentMembers(astBuilder, name, aggTypeDeclBaseRef, request, ioResult, inBreadcrumbs); + auto containerDeclRef = facet->getDeclRef().as<ContainerDecl>(); + if (!containerDeclRef) + continue; - // There are further lookup steps that we can only perform when a - // semantic checking context is available to us. That means that - // during parsing, lookup will fail to find members under `name` - // if they required following these paths. + // Check for cases where we should skip this facet for lookup. // - if(semantics) + // If the facet doesn't correspond to a type, we can't lookup. + if (!facet->getType() || !facet->subtypeWitness) { - if(auto aggTypeDeclRef = aggTypeDeclBaseRef.as<AggTypeDecl>()) - { - // If the declaration we are looking at is a nominal type declaration, - // then we want to consider any `extension`s that have been associated - // directly with that type. - // - ensureDecl(request.semantics, aggTypeDeclRef.getDecl(), DeclCheckState::ReadyForLookup); - for(auto extDecl : getCandidateExtensions(aggTypeDeclRef, semantics)) - { - // Note: In this case `extDecl` is an extension that was declared to apply - // (conditionally) to `aggTypeDeclRef`, which is the decl-ref part of - // `superType`. Thus when looking for a substitution to apply to the - // extension, we need to apply it to `superType` and not to `leafType`. - // - auto extDeclRef = ApplyExtensionToType(request.semantics, extDecl, superType); - if (!extDeclRef) - continue; + continue; + } - // TODO: eventually we need to insert a breadcrumb here so that - // the constructed result can somehow indicate that a member - // was found through an extension. - // - _lookUpMembersInSuperTypeDeclImpl( - astBuilder, - name, - leafType, - superType, - leafIsSuperWitness, - extDeclRef, - request, - ioResult, - inBreadcrumbs); - } - } + // If we are looking up in an interface, and the lookup request told us + // to skip interfaces, we should do so here. + if (auto baseInterfaceDeclRef = containerDeclRef.as<InterfaceDecl>()) + { + if (int(request.options) & int(LookupOptions::IgnoreBaseInterfaces)) + continue; + } - // For both aggregate types and their `extension`s, we want lookup to follow - // through the declared inheritance relationships on each declaration. - // - ensureDecl(semantics, aggTypeDeclBaseRef.getDecl(), DeclCheckState::CanEnumerateBases); - for (auto inheritanceDeclRef : getMembersOfType<InheritanceDecl>(astBuilder, aggTypeDeclBaseRef)) - { - ensureDecl(semantics, inheritanceDeclRef.getDecl(), DeclCheckState::CanUseBaseOfInheritanceDecl); + // Some things that are syntactically `InheritanceDecl`s don't actually + // represent a subtype/supertype relationship, and thus we shouldn't + // include members from the base type when doing lookup in the + // derived type. + // + // TODO: this check currently only works when the facet is a direct + // basee type of the type we are looking up in. This is OK because the + // only case where we use `IgnoreForLookupModifier` is for skipping the + // underlying int type of an enum type. We should either makes this + // check more general, or just explicitly detect this case here without + // relying on the modifier. + if (auto declaredSubtypeWitness = as<DeclaredSubtypeWitness>(facet->subtypeWitness)) + { + auto inheritanceDeclRef = declaredSubtypeWitness->declRef; + if (inheritanceDeclRef.getDecl()->hasModifier<IgnoreForLookupModifier>()) + continue; + } - // Some things that are syntactically `InheritanceDecl`s don't actually - // represent a subtype/supertype relationship, and thus we shouldn't - // include members from the base type when doing lookup in the - // derived type. - // - if(inheritanceDeclRef.getDecl()->hasModifier<IgnoreForLookupModifier>()) - continue; + // We are now going to lookup in the facet. - auto baseType = getSup(astBuilder, inheritanceDeclRef); - if( auto baseDeclRefType = as<DeclRefType>(baseType) ) - { - if( auto baseInterfaceDeclRef = baseDeclRefType->declRef.as<InterfaceDecl>() ) - { - if( int(request.options) & int(LookupOptions::IgnoreBaseInterfaces) ) - continue; - } - } + BreadcrumbInfo* newBreadcrumbs = inBreadcrumbs; + BreadcrumbInfo subtypeInfo; + if (facet->directness != Facet::Directness::Self) + { + // Depending on the type of the facet, we may want to specialize the + // declRef that we are going to lookup in. If the facet represents + // an extension, we should just lookup in the extension decl. + // + // If the facet is an extension to an interface type, we should + // specialize the interface declRef to the concrete type that this + // extension applied to. + // + // If the facet represents an implementation of interface type, + // we should also specialize the interface declRef with the concrete + // type info. + // + containerDeclRef = _maybeSpecializeSuperTypeDeclRef( + astBuilder, containerDeclRef, facet->getType(), facet->subtypeWitness) + .as<ContainerDecl>(); - _lookUpMembersInSuperType(astBuilder, name, leafType, leafIsSuperWitness, inheritanceDeclRef, request, ioResult, inBreadcrumbs); + // If we are looking up in a base type, we also need to make sure + // to create a breadcrumb to track the sub to super indirection. + if (facet->kind == Facet::Kind::Type) + { + subtypeInfo.kind = LookupResultItem_Breadcrumb::Kind::SuperType; + subtypeInfo.val = facet->subtypeWitness; + subtypeInfo.prev = inBreadcrumbs; + subtypeInfo.declRef = facet->getDeclRef(); + newBreadcrumbs = &subtypeInfo; } } + _lookUpDirectAndTransparentMembers(astBuilder, name, containerDeclRef, request, ioResult, newBreadcrumbs); } } @@ -611,7 +542,7 @@ static void _lookUpMembersInSuperTypeImpl( { auto declRef = declRefType->declRef; - _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, declRef, request, ioResult, inBreadcrumbs); + _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, declRef, request, ioResult, inBreadcrumbs); } else if (auto extractExistentialType = as<ExtractExistentialType>(superType)) { @@ -621,7 +552,7 @@ static void _lookUpMembersInSuperTypeImpl( // types, etc. used in the signature of a method to resolve correctly). // auto interfaceDeclRef = extractExistentialType->getSpecializedInterfaceDeclRef(); - _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, interfaceDeclRef, request, ioResult, inBreadcrumbs); + _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, interfaceDeclRef, request, ioResult, inBreadcrumbs); } else if( auto thisType = as<ThisType>(superType) ) { @@ -632,9 +563,7 @@ static void _lookUpMembersInSuperTypeImpl( // auto interfaceType = DeclRefType::create(astBuilder, thisType->interfaceDeclRef); - auto superIsInterfaceWitness = astBuilder->create<ThisTypeSubtypeWitness>(); - superIsInterfaceWitness->sub = superType; - superIsInterfaceWitness->sup = interfaceType; + auto superIsInterfaceWitness = astBuilder->getThisTypeSubtypeWitness(superType, interfaceType); auto leafIsInterfaceWitness = _makeSubtypeWitness( astBuilder, diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 4ff14fba7..0dcea9a14 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -2034,7 +2034,7 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower void _collectSubstitutionArgs(List<IRInst*>& operands, Substitutions* subst) { if (!subst) return; - _collectSubstitutionArgs(operands, subst->outer); + _collectSubstitutionArgs(operands, subst->getOuter()); if (auto genSubst = as<GenericSubstitution>(subst)) { for (auto arg : genSubst->getArgs()) @@ -3931,11 +3931,11 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> void _lowerSubstitutionEnv(IRGenContext* subContext, Substitutions* subst) { if(!subst) return; - _lowerSubstitutionEnv(subContext, subst->outer); + _lowerSubstitutionEnv(subContext, subst->getOuter()); if (auto genSubst = as<GenericSubstitution>(subst)) { - auto genDecl = genSubst->genericDecl; + auto genDecl = genSubst->getGenericDecl(); Index argCounter = 0; for( auto memberDecl: genDecl->members ) @@ -9415,7 +9415,7 @@ LoweredValInfo emitDeclRef( if(!canDeclLowerToAGeneric(decl)) { while(auto genericSubst = as<GenericSubstitution>(subst)) - subst = genericSubst->outer; + subst = genericSubst->getOuter(); } // In the simplest case, there is no specialization going @@ -9444,7 +9444,7 @@ LoweredValInfo emitDeclRef( LoweredValInfo genericVal = emitDeclRef( context, decl, - genericSubst->outer, + genericSubst->getOuter(), context->irBuilder->getGenericKind()); // There's no reason to specialize something that maps to a NULL pointer. @@ -9542,7 +9542,7 @@ LoweredValInfo emitDeclRef( // are lowered as generics, where the generic parameter represents // the `ThisType`. // - auto genericVal = emitDeclRef(context, decl, thisTypeSubst->outer, context->irBuilder->getGenericKind()); + auto genericVal = emitDeclRef(context, decl, thisTypeSubst->getOuter(), context->irBuilder->getGenericKind()); auto irGenericVal = getSimpleVal(context, genericVal); // In order to reference the member for a particular type, we diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp index de1b58999..4d94d5283 100644 --- a/source/slang/slang-mangle.cpp +++ b/source/slang/slang-mangle.cpp @@ -424,7 +424,7 @@ namespace Slang // in place for the parent generic declaration, or we don't. auto subst = findInnerMostGenericSubstitution(declRef.getSubst()); - if( subst && subst->genericDecl == parentGenericDeclRef.getDecl() ) + if( subst && subst->getGenericDecl() == parentGenericDeclRef.getDecl()) { // This is the case where we *do* have substitutions. emitRaw(context, "G"); diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index 3ef510990..f3f8f325e 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -135,6 +135,10 @@ namespace Slang else return kConversionCost_GeneralConversion; } + else if (fromInfo.tag == BaseType::Bool && toInfo.tag == BaseType::Int) + { + return kConversionCost_BoolToInt; + } // If we are converting from an unsigned integer type to // a signed integer type that is guaranteed to be larger, diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp index 4033dfff1..f70d2bd85 100644 --- a/source/slang/slang-syntax.cpp +++ b/source/slang/slang-syntax.cpp @@ -425,21 +425,34 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt // nested generics. // - // We are going to build up a list of substitutions that need - // to be applied to the decl-ref to make it specialized. - Substitutions* substsToApply = nullptr; - Substitutions** link = &substsToApply; - + // First, we collect all the generic parents. + ShortList<GenericDecl*> genericParents; Decl* dd = declRef.getDecl(); - for(;;) + for (;;) { Decl* childDecl = dd; Decl* parentDecl = dd->parentDecl; - if(!parentDecl) + if (!parentDecl) break; dd = parentDecl; + if (auto genericParentDecl = as<GenericDecl>(parentDecl)) + { + // Don't specialize any parameters of a generic. + if (childDecl != genericParentDecl->inner) + break; + genericParents.add(genericParentDecl); + } + } + + + Substitutions* outerSubst = nullptr; + for (Index i = genericParents.getCount()-1; i>=0; i--) + { + Decl* childDecl = genericParents[i]->inner; + Decl* parentDecl = genericParents[i]; + if(auto genericParentDecl = as<GenericDecl>(parentDecl)) { // Don't specialize any parameters of a generic. @@ -448,18 +461,24 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt // We have a generic ancestor, but do we have an substitutions for it? GenericSubstitution* foundSubst = nullptr; - for(auto s = declRef.getSubst(); s; s = s->outer) + for(auto s = declRef.getSubst(); s; s = s->getOuter()) { auto genSubst = as<GenericSubstitution>(s); if(!genSubst) continue; - if(genSubst->genericDecl != genericParentDecl) + if(genSubst->getGenericDecl() != genericParentDecl) continue; // Okay, we found a matching substitution, - // so there is nothing to be done. + // so we just grab the args from the matching subst instead. foundSubst = genSubst; + if (foundSubst->getOuter() != outerSubst) + { + foundSubst = astBuilder->getOrCreateGenericSubstitution( + outerSubst, foundSubst->getGenericDecl(), foundSubst->getArgs()); + } + break; } @@ -469,19 +488,21 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt astBuilder, semantics, genericParentDecl, - nullptr); - - *link = newSubst; - link = &newSubst->outer; + outerSubst); + outerSubst = newSubst; + } + else + { + outerSubst = foundSubst; } } } - if(!substsToApply) + if(!outerSubst) return declRef; int diff = 0; - return declRef.substituteImpl(astBuilder, substsToApply, &diff); + return declRef.substituteImpl(astBuilder, outerSubst, &diff); } // TODO: need to figure out how to unify this with the logic @@ -494,14 +515,14 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt if (auto builtinMod = declRef.getDecl()->findModifier<BuiltinTypeModifier>()) { - auto type = astBuilder->create<BasicExpressionType>(builtinMod->tag); + auto type = astBuilder->getOrCreate<BasicExpressionType>(builtinMod->tag); type->declRef = declRef; return type; } else if (auto magicMod = declRef.getDecl()->findModifier<MagicTypeModifier>()) { GenericSubstitution* subst = nullptr; - for(auto s = declRef.getSubst(); s; s = s->outer) + for(auto s = declRef.getSubst(); s; s = s->getOuter()) { if(auto genericSubst = as<GenericSubstitution>(s)) { @@ -561,7 +582,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt else if (magicMod->magicName == "TextureSampler") { SLANG_ASSERT(subst && subst->getArgs().getCount() >= 1); - auto textureType = astBuilder->create<TextureSamplerType>( + auto textureType = astBuilder->getOrCreate<TextureSamplerType>( TextureFlavor(magicMod->tag), ExtractGenericArgType(subst->getArgs()[0])); textureType->declRef = declRef; @@ -675,7 +696,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt } else { - return astBuilder->getOrCreateDeclRefType(declRef.declRefBase); + return astBuilder->getOrCreate<DeclRefType>(declRef.declRefBase); } } @@ -683,7 +704,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt GenericSubstitution* findInnerMostGenericSubstitution(Substitutions* subst) { - for(Substitutions* s = subst; s; s = s->outer) + for(Substitutions* s = subst; s; s = s->getOuter()) { if(auto genericSubst = as<GenericSubstitution>(s)) return genericSubst; @@ -803,7 +824,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt // Does it already have a specialization for that generic? if(auto specGenericSubst = as<GenericSubstitution>(substsToSpecialize)) { - if(specGenericSubst->genericDecl == ancestorGenericDecl) + if(specGenericSubst->getGenericDecl() == ancestorGenericDecl) { // Yes. We have an existing specialization, so we will // keep one matching it in place. @@ -811,7 +832,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt auto restSubst = specializeSubstitutions( astBuilder, ancestorGenericDecl->parentDecl, - specGenericSubst->outer, + specGenericSubst->getOuter(), substsToApply, &diff); @@ -835,13 +856,13 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt // "default" specializations, this case shouldn't // actually come up. // - for(auto s = substsToApply; s; s = s->outer) + for(auto s = substsToApply; s; s = s->getOuter()) { auto appGenericSubst = as<GenericSubstitution>(s); if(!appGenericSubst) continue; - if(appGenericSubst->genericDecl != ancestorGenericDecl) + if(appGenericSubst->getGenericDecl() != ancestorGenericDecl) continue; // The substitutions we are applying are trying @@ -858,7 +879,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt &diff); GenericSubstitution* firstSubst = astBuilder->getOrCreateGenericSubstitution( - ancestorGenericDecl, appGenericSubst->getArgs(), restSubst); + restSubst, ancestorGenericDecl, appGenericSubst->getArgs()); (*ioDiff)++; return firstSubst; @@ -882,7 +903,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt auto restSubst = specializeSubstitutions( astBuilder, ancestorInterfaceDecl->parentDecl, - specThisTypeSubst->outer, + specThisTypeSubst->getOuter(), substsToApply, &diff); @@ -912,7 +933,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt // reference. if (declToSpecialize != ancestorInterfaceDecl) { - for (auto s = substsToApply; s; s = s->outer) + for (auto s = substsToApply; s; s = s->getOuter()) { auto appThisTypeSubst = as<ThisTypeSubstitution>(s); if (!appThisTypeSubst) @@ -1049,7 +1070,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt if(thisTypeSubst->interfaceDecl == interfaceDecl) { // Strip away that specializations that apply to the interface. - substToApply = thisTypeSubst->outer; + substToApply = thisTypeSubst->getOuter(); } } } @@ -1064,10 +1085,10 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt // if(auto genericSubst = as<GenericSubstitution>(substToApply)) { - if(genericSubst->genericDecl == parentGenericDecl) + if(genericSubst->getGenericDecl() == parentGenericDecl) { // Strip away the specializations that were applied to the parent. - substToApply = genericSubst->outer; + substToApply = genericSubst->getOuter(); } } } @@ -1207,7 +1228,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt const Substitutions* substs, InterfaceDecl* interfaceDecl) { - for(const Substitutions* s = substs; s; s = s->outer) + for(const Substitutions* s = substs; s; s = s->getOuter()) { auto thisTypeSubst = as<ThisTypeSubstitution>(s); if(!thisTypeSubst) @@ -1230,7 +1251,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt auto substAssocTypeDecl = substDeclRef.getDecl(); - for (auto s = substDeclRef.getSubst(); s; s = s->outer) + for (auto s = substDeclRef.getSubst(); s; s = s->getOuter()) { auto thisSubst = as<ThisTypeSubstitution>(s); if (!thisSubst) @@ -1346,14 +1367,14 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt } // Look for generic substitutions on this type. - for (const Substitutions* subst = substitutions; subst; subst = subst->outer) + for (const Substitutions* subst = substitutions; subst; subst = subst->getOuter()) { auto genericSubstitution = Slang::as<GenericSubstitution>(subst); if (!genericSubstitution) continue; // If the substitution is for this type, print it. - if (genericSubstitution->genericDecl == decl) + if (genericSubstitution->getGenericDecl() == decl) { out << "<"; bool isFirst = true; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index d8174190b..760a119d1 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -4004,7 +4004,7 @@ struct SpecializationArgModuleCollector : ComponentTypeVisitor void collectReferencedModules(SubstitutionSet const& substitutions) { - for(auto subst = substitutions.substitutions; subst; subst = subst->outer) + for(auto subst = substitutions.substitutions; subst; subst = subst->getOuter()) { collectReferencedModules(subst); } @@ -5210,6 +5210,7 @@ SlangResult EndToEndCompileRequest::EndToEndCompileRequest::compile() { StringBuilder perfResult; PerformanceProfiler::getProfiler()->getResult(perfResult); + perfResult << "\nType Dictionary Size: " << getSession()->m_typeDictionarySize << "\n"; getSink()->diagnose(SourceLoc(), Diagnostics::performanceBenchmarkResult, perfResult.produceString()); } diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 1db7b9bce..74b625183 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -10,30 +10,25 @@ </Expand> </Type> <Type Name="Slang::DeclRef<*>"> - <SmartPointer Usage="Minimal">declRefBase ? ($T1*)(declRefBase->decl) : ($T1*)0</SmartPointer> <DisplayString Condition="declRefBase == 0">DeclRef nullptr</DisplayString> <DisplayString Condition="declRefBase != 0">{*declRefBase}</DisplayString> - <!-- <Expand> - <ExpandedItem>decl ? ($T1*)(decl) : ($T1*)0</ExpandedItem> + <ExpandedItem>declRefBase ? ($T1*)(declRefBase->decl) : ($T1*)0</ExpandedItem> <Synthetic Name="[Substitutions]"> <Expand> <LinkedListItems> - <HeadPointer>substitutions.substitutions</HeadPointer> + <HeadPointer>declRefBase->substitutions</HeadPointer> <NextPointer>outer</NextPointer> <ValueNode>this</ValueNode> </LinkedListItems> </Expand> </Synthetic> </Expand> - --> </Type> <Type Name="Slang::DeclRefBase"> - <SmartPointer Usage="Minimal">decl</SmartPointer> <DisplayString Condition="decl != 0 && substitutions != 0">{*decl}{*substitutions}</DisplayString> <DisplayString Condition="decl != 0">{*decl}</DisplayString> <DisplayString Condition="decl == 0">DeclRefBase nullptr</DisplayString> - <!-- <Expand> <ExpandedItem>decl</ExpandedItem> <Synthetic Name="[Substitutions]"> @@ -46,7 +41,6 @@ </Expand> </Synthetic> </Expand> - --> </Type> <Type Name="Slang::GenericSubstitution"> <DisplayString>GenSubst {(*genericDecl).nameAndLoc}</DisplayString> @@ -103,18 +97,6 @@ </CustomListItems> <Item Name="[value]" Condition="m_op == kIROp_StringLit">((IRStringLit*)this)->value.stringVal.chars,[((IRStringLit*)this)->value.stringVal.numChars]s8</Item> <Item Name="[value]" Condition="m_op == kIROp_IntLit">((IRIntLit*)this)->value.intVal</Item> - <!-- - <Synthetic Name="[operands]"> - <DisplayString>{{count = {operandCount}}}</DisplayString> - <Expand> - <Item Name="[count]">operandCount</Item> - <ArrayItems> - <Size>operandCount</Size> - <ValuePointer>(IRUse*)(&(typeUse) + 1)</ValuePointer> - </ArrayItems> - </Expand> - </Synthetic> - --> <CustomListItems MaxItemsPerView="10"> <Variable Name="index" InitialValue="0"/> <Variable Name="nameDecoration" InitialValue="(IRInst*)nullptr"/> |
