summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/core/core.natvis38
-rw-r--r--source/core/slang-dictionary.h36
-rw-r--r--source/slang/slang-ast-base.h32
-rw-r--r--source/slang/slang-ast-builder.cpp17
-rw-r--r--source/slang/slang-ast-builder.h24
-rw-r--r--source/slang/slang-ast-print.cpp2
-rw-r--r--source/slang/slang-ast-substitutions.cpp2
-rw-r--r--source/slang/slang-ast-support-types.h1
-rw-r--r--source/slang/slang-ast-type.cpp6
-rw-r--r--source/slang/slang-ast-val.cpp8
-rw-r--r--source/slang/slang-ast-val.h6
-rw-r--r--source/slang/slang-check-conformance.cpp15
-rw-r--r--source/slang/slang-check-constraint.cpp8
-rw-r--r--source/slang/slang-check-decl.cpp53
-rw-r--r--source/slang/slang-check-expr.cpp8
-rw-r--r--source/slang/slang-check-impl.h24
-rw-r--r--source/slang/slang-check-inheritance.cpp3
-rw-r--r--source/slang/slang-check-overload.cpp17
-rw-r--r--source/slang/slang-check-shader.cpp8
-rw-r--r--source/slang/slang-check-type.cpp2
-rwxr-xr-xsource/slang/slang-compiler.h1
-rw-r--r--source/slang/slang-ir-legalize-types.cpp55
-rw-r--r--source/slang/slang-ir-lower-generic-function.cpp1
-rw-r--r--source/slang/slang-ir-redundancy-removal.cpp9
-rw-r--r--source/slang/slang-ir-simplify-cfg.cpp4
-rw-r--r--source/slang/slang-ir-specialize.cpp344
-rw-r--r--source/slang/slang-ir-util.h3
-rw-r--r--source/slang/slang-ir.cpp4
-rw-r--r--source/slang/slang-ir.h12
-rw-r--r--source/slang/slang-lookup.cpp295
-rw-r--r--source/slang/slang-lower-to-ir.cpp12
-rw-r--r--source/slang/slang-mangle.cpp2
-rw-r--r--source/slang/slang-stdlib.cpp4
-rw-r--r--source/slang/slang-syntax.cpp91
-rw-r--r--source/slang/slang.cpp3
-rw-r--r--source/slang/slang.natvis22
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&lt;*,*&gt;">
- <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 &gt;= bucketSizeMinusOne + 1">
+ <If Condition="iBucket &gt;= m_bucketCountMinusOne">
<Break/>
</If>
<Exec>
- isDeleted = marks.m_buffer.m_count &gt; (iBucket*2+1)/32
- ? ((marks.m_buffer.m_buffer[(iBucket*2+1)/32]&amp;(1&lt;&lt;(iBucket*2+1)%32)) != 0)
+ isDeleted = m_marks.m_buffer.m_count &gt; (iBucket*2+1)/32
+ ? ((m_marks.m_buffer.m_buffer[(iBucket*2+1)/32]&amp;(1&lt;&lt;(iBucket*2+1)%32)) != 0)
: 0
</Exec>
<Exec>
- isEmpty = marks.m_buffer.m_count &gt; (iBucket*2)/32
- ? ((marks.m_buffer.m_buffer[(iBucket*2)/32]&amp;(1&lt;&lt;(iBucket*2)%32)) == 0)
+ isEmpty = m_marks.m_buffer.m_count &gt; (iBucket*2)/32
+ ? ((m_marks.m_buffer.m_buffer[(iBucket*2)/32]&amp;(1&lt;&lt;(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&lt;*,*&gt;">
- <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&lt;*&gt;">
- <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 &amp;&amp; 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*)(&amp;(typeUse) + 1)</ValuePointer>
- </ArrayItems>
- </Expand>
- </Synthetic>
- -->
<CustomListItems MaxItemsPerView="10">
<Variable Name="index" InitialValue="0"/>
<Variable Name="nameDecoration" InitialValue="(IRInst*)nullptr"/>