diff options
| author | Yong He <yonghe@outlook.com> | 2024-02-20 15:37:11 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-20 15:37:11 -0800 |
| commit | a62be597990966b9516995650baf750ee6a0146b (patch) | |
| tree | 1741b3d5b5859319f278aa6ab821a2f801fd8e08 /source | |
| parent | 4d20fd329956ac89408b1628a8291fea01bc9a6d (diff) | |
Support link time type specialization. (#3604)
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/slang-list.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ast-decl.cpp | 15 | ||||
| -rw-r--r-- | source/slang/slang-ast-decl.h | 13 | ||||
| -rw-r--r-- | source/slang/slang-ast-dump.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-check-conformance.cpp | 53 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 40 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 14 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 5 |
12 files changed, 149 insertions, 12 deletions
diff --git a/source/core/slang-list.h b/source/core/slang-list.h index 250b6dc49..c0fe28937 100644 --- a/source/core/slang-list.h +++ b/source/core/slang-list.h @@ -570,7 +570,7 @@ namespace Slang } template<typename T2> - int binarySearch(const T2& obj) + Index binarySearch(const T2& obj) { return binarySearch(obj, [](T & curObj, const T2 & thatObj)->int diff --git a/source/slang/slang-ast-decl.cpp b/source/slang/slang-ast-decl.cpp index 9dbd006a0..cd9c43410 100644 --- a/source/slang/slang-ast-decl.cpp +++ b/source/slang/slang-ast-decl.cpp @@ -136,4 +136,19 @@ InterfaceDecl* ThisTypeConstraintDecl::getInterfaceDecl() return as<InterfaceDecl>(parentDecl->parentDecl); } +void AggTypeDecl::addTag(TypeTag tag) +{ + typeTags = (TypeTag)((int)tag | (int)tag); +} + +bool AggTypeDecl::hasTag(TypeTag tag) +{ + return ((int)typeTags & (int)tag) != 0; +} + +void AggTypeDecl::unionTagsWith(TypeTag other) +{ + addTag(other); +} + } // namespace Slang diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index 5d8023eaf..7a4d46947 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -130,11 +130,24 @@ class ExtensionDecl : public AggTypeDeclBase TypeExp targetType; }; +enum class TypeTag +{ + None = 0, + Unsized = 1, + Incomplete = 2 +}; + // Declaration of a type that represents some sort of aggregate class AggTypeDecl : public AggTypeDeclBase { SLANG_ABSTRACT_AST_CLASS(AggTypeDecl) + TypeTag typeTags = TypeTag::None; + + void unionTagsWith(TypeTag other); + void addTag(TypeTag tag); + bool hasTag(TypeTag tag); + FilteredMemberList<VarDecl> getFields() { return getMembersOfType<VarDecl>(); diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp index 9c40fb12b..ccd9b9ee7 100644 --- a/source/slang/slang-ast-dump.cpp +++ b/source/slang/slang-ast-dump.cpp @@ -343,6 +343,10 @@ struct ASTDumpContext { m_writer->emit((int)v); } + void dump(TypeTag tag) + { + m_writer->emit((int)tag); + } void dump(const String& string) { dump(string.getUnownedSlice()); diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index c1984910c..d3529b963 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -1503,6 +1503,9 @@ namespace Slang // The type witnessesd by the witness table (a concrete type). Type* witnessedType; + // Whether or not this witness table is an extern declaration. + bool isExtern = false; + // Satisfying values of each requirement. List<KeyValuePair<Decl*, RequirementWitness>> m_requirements; diff --git a/source/slang/slang-check-conformance.cpp b/source/slang/slang-check-conformance.cpp index 4376b1135..726572d08 100644 --- a/source/slang/slang-check-conformance.cpp +++ b/source/slang/slang-check-conformance.cpp @@ -242,6 +242,59 @@ namespace Slang return isSubtype(type, m_astBuilder->getDiffInterfaceType()); } + bool SemanticsVisitor::doesTypeHaveTag(Type* type, TypeTag tag) + { + if (auto arrayType = as<ArrayExpressionType>(type)) + { + return doesTypeHaveTag(arrayType->getElementType(), tag); + } + if (auto modifiedType = as<ModifiedType>(type)) + { + return doesTypeHaveTag(modifiedType->getBase(), tag); + } + if (auto declRefType = as<DeclRefType>(type)) + { + if (auto aggTypeDecl = as<AggTypeDecl>(declRefType->getDeclRef())) + return aggTypeDecl.getDecl()->hasTag(tag); + } + return false; + } + + TypeTag SemanticsVisitor::getTypeTags(Type* type) + { + if (auto arrayType = as<ArrayExpressionType>(type)) + { + return getTypeTags(arrayType->getElementType()); + } + if (auto modifiedType = as<ModifiedType>(type)) + { + return getTypeTags(modifiedType->getBase()); + } + if (auto declRefType = as<DeclRefType>(type)) + { + if (auto aggTypeDecl = as<AggTypeDecl>(declRefType->getDeclRef())) + return aggTypeDecl.getDecl()->typeTags; + } + return TypeTag::None; + } + + + Type* SemanticsVisitor::getBufferElementType(Type* type) + { + if (auto arrType = as<ArrayExpressionType>(type)) + return getBufferElementType(arrType->getElementType()); + if (auto modifiedType = as<ModifiedType>(type)) + return getBufferElementType(modifiedType->getBase()); + if (auto constantBuffer = as<ConstantBufferType>(type)) + return constantBuffer->getElementType(); + if (auto structuredBuffer = as<HLSLStructuredBufferTypeBase>(type)) + return structuredBuffer->getElementType(); + if (auto storageBuffer = as<GLSLShaderStorageBufferType>(type)) + return storageBuffer->getElementType(); + return nullptr; + } + + SubtypeWitness* SemanticsVisitor::tryGetInterfaceConformanceWitness( Type* type, Type* interfaceType) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 3fb2725e2..dc888ccda 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -302,6 +302,8 @@ namespace Slang void visitFunctionDeclBase(FunctionDeclBase* funcDecl); void visitParamDecl(ParamDecl* paramDecl); + + void visitAggTypeDecl(AggTypeDecl* aggTypeDecl); }; template<typename VisitorType> @@ -1705,6 +1707,15 @@ namespace Slang } } + // Propagate type tags. + if (auto parentAggTypeDecl = as<AggTypeDecl>(getParentDecl(varDecl))) + { + if (auto varDeclRefType = as<DeclRefType>(varDecl->type.type)) + { + parentAggTypeDecl->unionTagsWith(getTypeTags(varDecl->type.type)); + } + } + checkVisibility(varDecl); } @@ -1722,11 +1733,20 @@ namespace Slang { addModifier(structDecl, m_astBuilder->create<NVAPIMagicModifier>()); } + + if (structDecl->hasModifier<ExternModifier>()) + { + structDecl->addTag(TypeTag::Incomplete); + } checkVisibility(structDecl); } void SemanticsDeclHeaderVisitor::visitClassDecl(ClassDecl* classDecl) { + if (classDecl->hasModifier<ExternModifier>()) + { + classDecl->addTag(TypeTag::Incomplete); + } checkVisibility(classDecl); } @@ -1812,6 +1832,13 @@ namespace Slang varDecl->initExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate); } } + if (auto elementType = getBufferElementType(varDecl->getType())) + { + if (doesTypeHaveTag(elementType, TypeTag::Incomplete)) + { + getSink()->diagnose(varDecl->type.exp->loc, Diagnostics::incompleteTypeCannotBeUsedInBuffer, elementType); + } + } maybeRegisterDifferentiableType(getASTBuilder(), varDecl->getType()); } @@ -4784,6 +4811,9 @@ namespace Slang SubtypeWitness* subIsSuperWitness, WitnessTable* witnessTable) { + if (witnessTable->isExtern) + return true; + if (auto supereclRefType = as<DeclRefType>(superType)) { auto superTypeDeclRef = supereclRefType->getDeclRef(); @@ -4896,6 +4926,7 @@ namespace Slang witnessTable = new WitnessTable(); witnessTable->baseType = superType; witnessTable->witnessedType = subType; + witnessTable->isExtern = parentDecl->hasModifier<ExternModifier>(); inheritanceDecl->witnessTable = witnessTable; } @@ -5179,6 +5210,7 @@ namespace Slang // order) is allowed to declare a base `class` type. // SLANG_OUTER_SCOPE_CONTEXT_DECL_RAII(this, decl); + Index inheritanceClauseCounter = 0; for (auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) { @@ -6544,6 +6576,14 @@ namespace Slang } } + void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) + { + if (aggTypeDecl->hasTag(TypeTag::Incomplete) && aggTypeDecl->hasModifier<HLSLExportModifier>()) + { + getSink()->diagnose(aggTypeDecl->loc, Diagnostics::cannotExportIncompleteType, aggTypeDecl); + } + } + void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src) { dest->modifiers = src->modifiers; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 3af85b73d..ba8e2f4cd 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1957,6 +1957,12 @@ namespace Slang bool isTypeDifferentiable(Type* type); + bool doesTypeHaveTag(Type* type, TypeTag tag); + + TypeTag getTypeTags(Type* type); + + Type* getBufferElementType(Type* type); + /// Check whether `subType` is a sub-type of `superTypeDeclRef`, /// and return a witness to the sub-type relationship if it holds /// (return null otherwise). diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 9117eb6ec..a4e906ac9 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -1109,7 +1109,8 @@ namespace Slang case ASTNodeType::HLSLExportModifier: case ASTNodeType::ExternCppModifier: return as<VarDeclBase>(decl) || as<AggTypeDeclBase>(decl) || as<NamespaceDeclBase>(decl) || as<CallableDecl>(decl) - || as<TypeDefDecl>(decl) || as<PropertyDecl>(decl) || as<SyntaxDecl>(decl) || as<AttributeDecl>(decl); + || as<TypeDefDecl>(decl) || as<PropertyDecl>(decl) || as<SyntaxDecl>(decl) || as<AttributeDecl>(decl) + || as<InheritanceDecl>(decl); case ASTNodeType::ExportedModifier: return as<ImportDecl>(decl); diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index ac1f9aff9..722085744 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -438,6 +438,9 @@ DIAGNOSTIC(31155, Error, customDerivativeNotAllowedForMemberFunctionsOfDifferent DIAGNOSTIC(31200, Warning, deprecatedUsage, "$0 has been deprecated: $1") DIAGNOSTIC(31201, Error, modifierNotAllowed, "modifier '$0' is not allowed here.") DIAGNOSTIC(31202, Error, duplicateModifier, "modifier '$0' is redundant or conflicting with existing modifier '$1'") +DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'") +DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer") + // Enums DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'") diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 8531e4029..b560bb156 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -657,17 +657,11 @@ bool isFromStdLib(Decl* decl) bool isImportedDecl(IRGenContext* context, Decl* decl) { // If the declaration has the extern attribute then it must be imported - // from another module + // from another module. + // Note that `extern` declarations will have a mangled name that does not + // include the module name so the linking step can resolve them correctly. // - // The [__extern] attribute is a very special case feature (aka "a hack") that allows a symbol to be declared - // as if it is part of the current module for AST purposes, but then expects to be imported from another IR module. - // For that linkage to work, both the exporting and importing modules must have the same name (which would - // usually indicate that they are the same module). - // - // Note that in practice for matching during linking uses the fully qualified name - including module name. - // Thus using extern __attribute isn't useful for symbols that are imported via `import`, only symbols - // that notionally come from the same module but are split into separate compilations (as can be done with -module-name) - if (decl->findModifier<ExternAttribute>()) + if (decl->findModifier<ExternAttribute>() || decl->findModifier<ExternModifier>()) { return true; } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index e0ffba53c..b89b93138 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -3232,6 +3232,9 @@ namespace Slang inheritanceDecl->base = base; AddMember(decl, inheritanceDecl); + + if (parser->pendingModifiers->hasModifier<ExternModifier>()) + addModifier(inheritanceDecl, parser->astBuilder->create<ExternModifier>()); } while (AdvanceIf(parser, TokenType::Comma)); } @@ -4730,6 +4733,8 @@ namespace Slang // We allow for an inheritance clause on a `struct` // so that it can conform to interfaces. parseOptionalInheritanceClause(this, rs); + if (AdvanceIf(this, TokenType::Semicolon)) + return rs; parseDeclBody(this, rs); return rs; }); |
