beanz created this revision. beanz added reviewers: Anastasia, spyffe, kuhar, bogner, python3kgae. Herald added a project: All. beanz requested review of this revision. Herald added a project: clang.
Most of the change here is fleshing out the HLSLExternalSemaSource with builder implementations to build the builtin types. Eventually, I may move some of this code into tablegen or a more managable declarative file but I want to get the AST generation logic ready first. This code adds two new types into the HLSL AST, `hlsl::Resource` and `hlsl::RWBuffer`. The `Resource` type is just a wrapper around a handle identifier, and is largely unused in source. It will morph a bit over time as I work on getting the source compatability correct, but for now it is a reasonable stand-in. The `RWBuffer` type is not ready for use. I'm posting this change for review because it adds a lot of infrastructure code and is testable. There is one change to clang code outside the HLSL-specific logic here, which addresses a behavior change introduced a long time ago in 967d438439ac. That change resulted in unintentionally breaking situations where an incomplete template declaration was provided from an AST source, and needed to be completed later by the external AST. That situation doesn't happen in the normal AST importer flow, but can happen when an AST source provides incomplete declarations of templates. The solution is to annotate template specializations of incomplete types with the HasExternalLexicalSource bit from the base template. Depends on D128012 <https://reviews.llvm.org/D128012>. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D128569 Files: clang/include/clang/Basic/Builtins.def clang/include/clang/Sema/HLSLExternalSemaSource.h clang/lib/AST/DeclTemplate.cpp clang/lib/Sema/HLSLExternalSemaSource.cpp clang/test/AST/HLSL/RWBuffer-AST.hlsl clang/test/AST/HLSL/ResourceStruct.hlsl clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
Index: clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl =================================================================== --- /dev/null +++ clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -verify %s + +Resource ResourceDescriptorHeap[5]; +typedef vector<float, 3> float3; + +RWBuffer<float3> Buffer; + +[numthreads(1,1,1)] +void main() { + (void)Buffer.h; // expected-error {{'h' is a private member of 'hlsl::RWBuffer<float __attribute__((ext_vector_type(3)))>'}} + // expected-note@* {{implicitly declared private here}} +} Index: clang/test/AST/HLSL/ResourceStruct.hlsl =================================================================== --- /dev/null +++ clang/test/AST/HLSL/ResourceStruct.hlsl @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -fsyntax-only -ast-dump %s | FileCheck %s + +// CHECK: NamespaceDecl {{.*}} implicit hlsl +// CHECK: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class Resource definition +// CHECK-NEXT: DefinitionData pass_in_registers standard_layout trivially_copyable trivial literal +// CHECK-NEXT: DefaultConstructor exists trivial needs_implicit +// CHECK-NEXT: CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'int' Index: clang/test/AST/HLSL/RWBuffer-AST.hlsl =================================================================== --- /dev/null +++ clang/test/AST/HLSL/RWBuffer-AST.hlsl @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -fsyntax-only -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -fsyntax-only -ast-dump %s | FileCheck %s + +// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWBuffer +// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type +// EMPTY-NEXT: TemplateArgument type 'float' +// EMPTY-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' +// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class RWBuffer +// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final + +// There should be no more occurrances of RWBuffer +// EMPTY-NOT: RWBuffer + +#ifndef EMPTY + +RWBuffer<float> Buffer; + +#endif + +// CHECK: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class Resource definition +// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'int' + +// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWBuffer +// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type +// CHECK-NEXT: TemplateArgument type 'float' +// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' +// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition + +// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'int' +// CHECK-NEXT: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class RWBuffer definition + +// CHECK: TemplateArgument type 'float' +// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' +// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'int' Index: clang/lib/Sema/HLSLExternalSemaSource.cpp =================================================================== --- clang/lib/Sema/HLSLExternalSemaSource.cpp +++ clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -15,8 +15,160 @@ #include "clang/Basic/AttrKinds.h" #include "clang/Sema/Sema.h" +#include <functional> + using namespace clang; +namespace { + +struct TemplateParameterListBuilder; + +struct BuiltinTypeDeclBuilder { + CXXRecordDecl *Record = nullptr; + ClassTemplateDecl *Template = nullptr; + NamespaceDecl *HLSLNamespace = nullptr; + + BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) { + Record->startDefinition(); + Template = Record->getDescribedClassTemplate(); + } + + BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name) + : HLSLNamespace(Namespace) { + ASTContext &AST = S.getASTContext(); + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + + Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::TTK_Class, + HLSLNamespace, SourceLocation(), + SourceLocation(), &II, nullptr, true); + Record->setImplicit(true); + Record->setLexicalDeclContext(HLSLNamespace); + Record->setHasExternalLexicalStorage(); + + // Don't let anyone derive from built-in types + Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(), + AttributeCommonInfo::AS_Keyword, + FinalAttr::Keyword_final)); + } + + ~BuiltinTypeDeclBuilder() { + if (HLSLNamespace && !Template) + HLSLNamespace->addDecl(Record); + } + + BuiltinTypeDeclBuilder & + addTemplateArgumentList(llvm::ArrayRef<NamedDecl *> TemplateArgs) { + ASTContext &AST = Record->getASTContext(); + + auto *ParamList = + TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), + TemplateArgs, SourceLocation(), nullptr); + Template = ClassTemplateDecl::Create( + AST, Record->getDeclContext(), SourceLocation(), + DeclarationName(Record->getIdentifier()), ParamList, Record); + Record->setDescribedClassTemplate(Template); + Template->setImplicit(true); + Template->setLexicalDeclContext(Record->getDeclContext()); + Record->getDeclContext()->addDecl(Template); + + // Requesting the class name specialization will fault in required types. + QualType T = Template->getInjectedClassNameSpecialization(); + T = AST.getInjectedClassNameType(Record, T); + return *this; + } + + BuiltinTypeDeclBuilder & + addMemberVariable(StringRef Name, QualType Type, + AccessSpecifier Access = AccessSpecifier::AS_private) { + assert(Record->isBeingDefined() && + "Definition must be started before adding members!"); + ASTContext &AST = Record->getASTContext(); + + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + TypeSourceInfo *MemTySource = + AST.getTrivialTypeSourceInfo(Type, SourceLocation()); + auto *Field = FieldDecl::Create( + AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource, + nullptr, false, InClassInitStyle::ICIS_NoInit); + Field->setAccess(Access); + Field->setImplicit(true); + Record->addDecl(Field); + return *this; + } + + BuiltinTypeDeclBuilder &addHandleMember() { + return addMemberVariable("h", Record->getASTContext().IntTy); + } + + BuiltinTypeDeclBuilder &startDefinition() { + Record->startDefinition(); + return *this; + } + + BuiltinTypeDeclBuilder &completeDefinition() { + assert(Record->isBeingDefined() && + "Definition must be started before completing it."); + + Record->completeDefinition(); + return *this; + } + + TemplateParameterListBuilder addTemplateArgumentList(); +}; + +struct TemplateParameterListBuilder { + BuiltinTypeDeclBuilder &Builder; + ASTContext &AST; + llvm::SmallVector<NamedDecl *> Params; + + TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) + : Builder(RB), AST(RB.Record->getASTContext()) {} + + ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } + + TemplateParameterListBuilder & + addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) { + unsigned Position = static_cast<unsigned>(Params.size()); + auto *Decl = TemplateTypeParmDecl::Create( + AST, Builder.Record->getDeclContext(), SourceLocation(), + SourceLocation(), /* TemplateDepth */ 0, Position, + &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false, + /* ParameterPack */ false); + if (!DefaultValue.isNull()) + Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue)); + + Params.emplace_back(Decl); + return *this; + } + + BuiltinTypeDeclBuilder &finalizeTemplateArgs() { + if (Params.empty()) + return Builder; + auto *ParamList = + TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), + Params, SourceLocation(), nullptr); + Builder.Template = ClassTemplateDecl::Create( + AST, Builder.Record->getDeclContext(), SourceLocation(), + DeclarationName(Builder.Record->getIdentifier()), ParamList, + Builder.Record); + Builder.Record->setDescribedClassTemplate(Builder.Template); + Builder.Template->setImplicit(true); + Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext()); + Builder.Record->getDeclContext()->addDecl(Builder.Template); + Params.clear(); + + QualType T = Builder.Template->getInjectedClassNameSpecialization(); + T = AST.getInjectedClassNameType(Builder.Record, T); + + return Builder; + } +}; + +TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() { + return TemplateParameterListBuilder(*this); +} +} // namespace + char HLSLExternalSemaSource::ID; HLSLExternalSemaSource::~HLSLExternalSemaSource() {} @@ -30,7 +182,8 @@ SourceLocation(), SourceLocation(), &HLSL, nullptr); HLSLNamespace->setImplicit(true); AST.getTranslationUnitDecl()->addDecl(HLSLNamespace); - defineHLSLVectorAlias(); + defineTrivialHLSLTypes(); + forwardDeclareHLSLTypes(); // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's // built in types inside a namespace, but we are planning to change that in @@ -96,3 +249,44 @@ Template->setLexicalDeclContext(Record->getDeclContext()); HLSLNamespace->addDecl(Template); } + +void HLSLExternalSemaSource::defineTrivialHLSLTypes() { + defineHLSLVectorAlias(); + + ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource") + .startDefinition() + .addHandleMember() + .completeDefinition() + .Record; +} + +void HLSLExternalSemaSource::forwardDeclareHLSLTypes() { + CXXRecordDecl *Decl; + Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") + .addTemplateArgumentList() + .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy) + .finalizeTemplateArgs() + .Record; + Completions.insert(std::make_pair( + Decl, std::bind(&HLSLExternalSemaSource::completeBufferType, this, + std::placeholders::_1))); +} + +void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) { + if (!isa<CXXRecordDecl>(Tag)) + return; + auto Record = cast<CXXRecordDecl>(Tag); + + // If this is a specialization, we need to get the underlying templated + // declaration and complete that. + if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record)) + Record = TDecl->getSpecializedTemplate()->getTemplatedDecl(); + auto It = Completions.find(Record); + if (It == Completions.end()) + return; + It->second(Record); +} + +void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) { + BuiltinTypeDeclBuilder(Record).addHandleMember().completeDefinition(); +} Index: clang/lib/AST/DeclTemplate.cpp =================================================================== --- clang/lib/AST/DeclTemplate.cpp +++ clang/lib/AST/DeclTemplate.cpp @@ -930,6 +930,14 @@ SpecializedTemplate, Args, PrevDecl); Result->setMayHaveOutOfDateDef(false); + // If the template decl is incomplete, copy the external lexical storage from + // the base template. This allows instantiations of incomplete types to + // complete using the external AST if the template's declaration came from an + // external AST. + if (!SpecializedTemplate->getTemplatedDecl()->isCompleteDefinition()) + Result->setHasExternalLexicalStorage( + SpecializedTemplate->getTemplatedDecl()->hasExternalLexicalStorage()); + Context.getTypeDeclType(Result, PrevDecl); return Result; } Index: clang/include/clang/Sema/HLSLExternalSemaSource.h =================================================================== --- clang/include/clang/Sema/HLSLExternalSemaSource.h +++ clang/include/clang/Sema/HLSLExternalSemaSource.h @@ -12,6 +12,8 @@ #ifndef CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H #define CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H +#include "llvm/ADT/DenseMap.h" + #include "clang/Sema/ExternalSemaSource.h" namespace clang { @@ -23,8 +25,16 @@ Sema *SemaPtr = nullptr; NamespaceDecl *HLSLNamespace; + CXXRecordDecl *ResourceDecl; + + using CompletionFunction = std::function<void(CXXRecordDecl *)>; + llvm::DenseMap<CXXRecordDecl *, CompletionFunction> Completions; void defineHLSLVectorAlias(); + void defineTrivialHLSLTypes(); + void forwardDeclareHLSLTypes(); + + void completeBufferType(CXXRecordDecl *Record); public: ~HLSLExternalSemaSource() override; @@ -36,6 +46,9 @@ /// Inform the semantic consumer that Sema is no longer available. void ForgetSema() override { SemaPtr = nullptr; } + + // Complete an incomplete HLSL builtin type + void CompleteType(TagDecl *Tag) override; }; } // namespace clang Index: clang/include/clang/Basic/Builtins.def =================================================================== --- clang/include/clang/Basic/Builtins.def +++ clang/include/clang/Basic/Builtins.def @@ -1700,6 +1700,9 @@ // HLSL LANGBUILTIN(WaveActiveCountBits, "Uib", "nc", HLSL_LANG) +LANGBUILTIN(__builtin_hlsl_get_resource_pointer, "v*", "i", HLSL_LANG) +LANGBUILTIN(__builtin_hlsl_get_resource_status, "Ui", "i", HLSL_LANG) +LANGBUILTIN(__builtin_hlsl_get_resource_dimensions1, "v", "iUi&", HLSL_LANG) // Builtins for XRay BUILTIN(__xray_customevent, "vcC*z", "")
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits