Author: Finn Plummer Date: 2025-05-12T09:59:46-07:00 New Revision: dd3d7cfe2e77f0f33b2952b1c965c87c9ea46eb4
URL: https://github.com/llvm/llvm-project/commit/dd3d7cfe2e77f0f33b2952b1c965c87c9ea46eb4 DIFF: https://github.com/llvm/llvm-project/commit/dd3d7cfe2e77f0f33b2952b1c965c87c9ea46eb4.diff LOG: [HLSL][RootSignature] Define and integrate rootsig clang attr and decl (#137690) - Defines a new declaration node `HLSLRootSignature` in `DeclNodes.td` that will consist of a `TrailingObjects` of the in-memory construction of the root signature, namely an array of `hlsl::rootsig::RootElement`s - Defines a new clang attr `RootSignature` which simply holds an identifier to a corresponding root signature declaration as above - Integrate the `HLSLRootSignatureParser` to construct the decl node in `ParseMicrosoftAttributes` and then attach the parsed attr with an identifier to the entry point function declaration. - Defines the various required declaration methods - Add testing that the declaration and reference attr are created correctly, and some syntactical error tests. It was previously proposed that we could have the root elements reference be stored directly as an additional member of the attribute and to not have a separate root signature decl. In contrast, by defining them separately as this change proposes, we will allow a unique root signature to have its own declaration in the AST tree. This allows us to only construct a single root signature for all duplicate root signature attributes. Having it located directly as a declaration might also prove advantageous when we consider root signature libraries. Resolves https://github.com/llvm/llvm-project/issues/119011 Added: clang/test/AST/HLSL/RootSignatures-AST.hlsl clang/test/SemaHLSL/RootSignature-err.hlsl Modified: clang/include/clang/AST/Decl.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/TextNodeDumper.h clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DeclNodes.td clang/include/clang/Parse/Parser.h clang/include/clang/Sema/SemaHLSL.h clang/lib/AST/CMakeLists.txt clang/lib/AST/Decl.cpp clang/lib/AST/DeclBase.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/CodeGen/CGDecl.cpp clang/lib/Parse/ParseDeclCXX.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaHLSL.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Serialization/ASTCommon.cpp clang/tools/libclang/CIndex.cpp llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 3faf63e395a08..f1013c57e008f 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -41,6 +41,7 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" @@ -5178,6 +5179,42 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { friend class ASTDeclWriter; }; +class HLSLRootSignatureDecl final + : public NamedDecl, + private llvm::TrailingObjects<HLSLRootSignatureDecl, + llvm::hlsl::rootsig::RootElement> { + friend TrailingObjects; + + unsigned NumElems; + + llvm::hlsl::rootsig::RootElement *getElems() { + return getTrailingObjects<llvm::hlsl::rootsig::RootElement>(); + } + + const llvm::hlsl::rootsig::RootElement *getElems() const { + return getTrailingObjects<llvm::hlsl::rootsig::RootElement>(); + } + + HLSLRootSignatureDecl(DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, + unsigned NumElems); + +public: + static HLSLRootSignatureDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, + ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements); + + static HLSLRootSignatureDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); + + ArrayRef<llvm::hlsl::rootsig::RootElement> getRootElements() const { + return {getElems(), NumElems}; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == HLSLRootSignature; } +}; + /// Insertion operator for diagnostics. This allows sending NamedDecl's /// into a diagnostic with <<. inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 3edc8684d0a19..23a8c4f1f7380 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1599,6 +1599,8 @@ DEF_TRAVERSE_DECL(EmptyDecl, {}) DEF_TRAVERSE_DECL(HLSLBufferDecl, {}) +DEF_TRAVERSE_DECL(HLSLRootSignatureDecl, {}) + DEF_TRAVERSE_DECL(LifetimeExtendedTemporaryDecl, { TRY_TO(TraverseStmt(D->getTemporaryExpr())); }) diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index ea3a0f058a8ed..1917a8ac29f05 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -408,6 +408,7 @@ class TextNodeDumper void VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D); void VisitHLSLBufferDecl(const HLSLBufferDecl *D); + void VisitHLSLRootSignatureDecl(const HLSLRootSignatureDecl *D); void VisitHLSLOutArgExpr(const HLSLOutArgExpr *E); void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S); void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 37c80ac90182c..ccd13a4cca4dd 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4735,6 +4735,17 @@ def Error : InheritableAttr { let Documentation = [ErrorAttrDocs]; } +/// HLSL Root Signature Attribute +def RootSignature : Attr { + /// [RootSignature(Signature)] + let Spellings = [Microsoft<"RootSignature">]; + let Args = [IdentifierArgument<"Signature">]; + let Subjects = SubjectList<[Function], + ErrorDiag, "'function'">; + let LangOpts = [HLSL]; + let Documentation = [RootSignatureDocs]; +} + def HLSLNumThreads: InheritableAttr { let Spellings = [Microsoft<"numthreads">]; let Args = [IntArgument<"X">, IntArgument<"Y">, IntArgument<"Z">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index cbb397cb31dfb..5fb5f16680b41 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8195,6 +8195,17 @@ and https://microsoft.github.io/hlsl-specs/proposals/0013-wave-size-range.html }]; } +def RootSignatureDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``RootSignature`` attribute applies to HLSL entry functions to define what +types of resources are bound to the graphics pipeline. + +For details about the use and specification of Root Signatures please see here: +https://learn.microsoft.com/en-us/windows/win32/direct3d12/root-signatures + }]; +} + def NumThreadsDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 20debd67a31a5..f1ebaf1db3fc0 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -111,5 +111,6 @@ def Empty : DeclNode<Decl>; def RequiresExprBody : DeclNode<Decl>, DeclContext; def LifetimeExtendedTemporary : DeclNode<Decl>; def HLSLBuffer : DeclNode<Named, "HLSLBuffer">, DeclContext; +def HLSLRootSignature : DeclNode<Named, "HLSLRootSignature">; def OpenACCDeclare : DeclNode<Decl, "#pragma acc declare">; def OpenACCRoutine : DeclNode<Decl, "#pragma acc routine">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 8b47a70890a7d..00538fd9a00b5 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3093,6 +3093,7 @@ class Parser : public CodeCompletionHandler { return AttrsParsed; } void ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs); + void ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs); void ParseMicrosoftAttributes(ParsedAttributes &Attrs); bool MaybeParseMicrosoftDeclSpecs(ParsedAttributes &Attrs) { if (getLangOpts().DeclSpecKeyword && Tok.is(tok::kw___declspec)) { diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 5d260acf92abb..e340547ff5f45 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,6 +119,7 @@ class SemaHLSL : public SemaBase { bool IsCompAssign); void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 26d4d04d46e95..b5cd14b915673 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS BinaryFormat Core FrontendOpenMP + FrontendHLSL Support TargetParser ) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 9cd1c71afd0f8..061fedb403ddd 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -5847,6 +5847,38 @@ bool HLSLBufferDecl::buffer_decls_empty() { return DefaultBufferDecls.empty() && decls_empty(); } +//===----------------------------------------------------------------------===// +// HLSLRootSignatureDecl Implementation +//===----------------------------------------------------------------------===// + +HLSLRootSignatureDecl::HLSLRootSignatureDecl(DeclContext *DC, + SourceLocation Loc, + IdentifierInfo *ID, + unsigned NumElems) + : NamedDecl(Decl::Kind::HLSLRootSignature, DC, Loc, DeclarationName(ID)), + NumElems(NumElems) {} + +HLSLRootSignatureDecl *HLSLRootSignatureDecl::Create( + ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, + ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements) { + HLSLRootSignatureDecl *RSDecl = + new (C, DC, + additionalSizeToAlloc<llvm::hlsl::rootsig::RootElement>( + RootElements.size())) + HLSLRootSignatureDecl(DC, Loc, ID, RootElements.size()); + auto *StoredElems = RSDecl->getElems(); + std::uninitialized_copy(RootElements.begin(), RootElements.end(), + StoredElems); + return RSDecl; +} + +HLSLRootSignatureDecl * +HLSLRootSignatureDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { + HLSLRootSignatureDecl *Result = new (C, ID) + HLSLRootSignatureDecl(nullptr, SourceLocation(), nullptr, /*NumElems=*/0); + return Result; +} + //===----------------------------------------------------------------------===// // ImportDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 2052c0c7cfe42..e30057e32d312 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -886,6 +886,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProperty: case MSProperty: case HLSLBuffer: + case HLSLRootSignature: return IDNS_Ordinary; case Label: return IDNS_Label; diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 3af6276b4baa1..112e902dfb374 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/Specifiers.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include <algorithm> #include <utility> @@ -3037,6 +3038,12 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) { dumpName(D); } +void TextNodeDumper::VisitHLSLRootSignatureDecl( + const HLSLRootSignatureDecl *D) { + dumpName(D); + llvm::hlsl::rootsig::dumpRootElements(OS, D->getRootElements()); +} + void TextNodeDumper::VisitHLSLOutArgExpr(const HLSLOutArgExpr *E) { OS << (E->isInOut() ? " inout" : " out"); } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index fe8c3cb20add3..4a8f7f6a42ecb 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -106,6 +106,7 @@ void CodeGenFunction::EmitDecl(const Decl &D, bool EvaluateConditionDecl) { case Decl::Binding: case Decl::UnresolvedUsingIfExists: case Decl::HLSLBuffer: + case Decl::HLSLRootSignature: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Record: // struct/union/class X; case Decl::CXXRecord: // struct/union/class X; [C++] diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 2aa7a5b1a0cb1..f1216331877ba 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -21,10 +21,12 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Parse/ParseHLSLRootSignature.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCodeCompletion.h" @@ -5311,6 +5313,90 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { } } +void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) { + assert(Tok.is(tok::identifier) && + "Expected an identifier to denote which MS attribute to consider"); + IdentifierInfo *RootSignatureIdent = Tok.getIdentifierInfo(); + assert(RootSignatureIdent->getName() == "RootSignature" && + "Expected RootSignature identifier for root signature attribute"); + + SourceLocation RootSignatureLoc = Tok.getLocation(); + ConsumeToken(); + + // Ignore the left paren location for now. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return; + } + + auto ProcessStringLiteral = [this]() -> std::optional<StringLiteral *> { + if (!isTokenStringLiteral()) + return std::nullopt; + + ExprResult StringResult = ParseUnevaluatedStringLiteralExpression(); + if (StringResult.isInvalid()) + return std::nullopt; + + if (auto Lit = dyn_cast<StringLiteral>(StringResult.get())) + return Lit; + + return std::nullopt; + }; + + auto StrLiteral = ProcessStringLiteral(); + if (!StrLiteral.has_value()) { + Diag(Tok, diag::err_expected_string_literal) + << /*in attributes...*/ 4 << RootSignatureIdent->getName(); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + T.consumeClose(); + return; + } + + // Construct our identifier + StringRef Signature = StrLiteral.value()->getString(); + auto Hash = llvm::hash_value(Signature); + std::string IdStr = "__hlsl_rootsig_decl_" + std::to_string(Hash); + IdentifierInfo *DeclIdent = &(Actions.getASTContext().Idents.get(IdStr)); + + LookupResult R(Actions, DeclIdent, SourceLocation(), + Sema::LookupOrdinaryName); + // Check if we have already found a decl of the same name, if we haven't + // then parse the root signature string and construct the in-memory elements + if (!Actions.LookupQualifiedName(R, Actions.CurContext)) { + SourceLocation SignatureLoc = + StrLiteral.value()->getExprLoc().getLocWithOffset( + 1); // offset 1 for '"' + // Invoke the root signature parser to construct the in-memory constructs + hlsl::RootSignatureLexer Lexer(Signature, SignatureLoc); + SmallVector<llvm::hlsl::rootsig::RootElement> RootElements; + hlsl::RootSignatureParser Parser(RootElements, Lexer, PP); + if (Parser.parse()) { + T.consumeClose(); + return; + } + + // Create the Root Signature + auto *SignatureDecl = HLSLRootSignatureDecl::Create( + Actions.getASTContext(), /*DeclContext=*/Actions.CurContext, + RootSignatureLoc, DeclIdent, RootElements); + SignatureDecl->setImplicit(); + Actions.PushOnScopeChains(SignatureDecl, getCurScope()); + } + + // Create the arg for the ParsedAttr + IdentifierLoc *ILoc = ::new (Actions.getASTContext()) + IdentifierLoc(RootSignatureLoc, DeclIdent); + + ArgsVector Args = {ILoc}; + + if (!T.consumeClose()) + Attrs.addNew(RootSignatureIdent, + SourceRange(RootSignatureLoc, T.getCloseLocation()), nullptr, + SourceLocation(), Args.data(), Args.size(), + ParsedAttr::Form::Microsoft()); +} + /// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// [MS] ms-attribute: @@ -5345,6 +5431,8 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) { break; if (Tok.getIdentifierInfo()->getName() == "uuid") ParseMicrosoftUuidAttributeArgs(Attrs); + else if (Tok.getIdentifierInfo()->getName() == "RootSignature") + ParseMicrosoftRootSignatureAttributeArgs(Attrs); else { IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b8801233942e1..377595639bef1 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7481,6 +7481,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, break; // HLSL attributes: + case ParsedAttr::AT_RootSignature: + S.HLSL().handleRootSignatureAttr(D, AL); + break; case ParsedAttr::AT_HLSLNumThreads: S.HLSL().handleNumThreadsAttr(D, AL); break; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 08bd22a262788..e295114d7617b 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -29,6 +29,7 @@ #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" @@ -950,6 +951,33 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); } +void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { + if (AL.getNumArgs() != 1) { + Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; + return; + } + + IdentifierInfo *Ident = AL.getArgAsIdent(0)->getIdentifierInfo(); + if (auto *RS = D->getAttr<RootSignatureAttr>()) { + if (RS->getSignature() != Ident) { + Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << RS; + return; + } + + Diag(AL.getLoc(), diag::warn_duplicate_attribute_exact) << RS; + return; + } + + LookupResult R(SemaRef, Ident, SourceLocation(), Sema::LookupOrdinaryName); + if (SemaRef.LookupQualifiedName(R, D->getDeclContext())) + if (auto *SignatureDecl = + dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) { + // Perform validation of constructs here + D->addAttr(::new (getASTContext()) + RootSignatureAttr(getASTContext(), AL, Ident)); + } +} + void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { llvm::VersionTuple SMVersion = getASTContext().getTargetInfo().getTriple().getOSVersion(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 08b3a423d1526..01065f22b34a8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -999,6 +999,11 @@ Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) { llvm_unreachable("HLSL buffer declarations cannot be instantiated"); } +Decl *TemplateDeclInstantiator::VisitHLSLRootSignatureDecl( + HLSLRootSignatureDecl *Decl) { + llvm_unreachable("HLSL root signature declarations cannot be instantiated"); +} + Decl * TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) { llvm_unreachable("pragma comment cannot be instantiated"); diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index ad277f19711ff..76eb8697b2afd 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -458,6 +458,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: case Decl::HLSLBuffer: + case Decl::HLSLRootSignature: case Decl::OpenACCDeclare: case Decl::OpenACCRoutine: return false; diff --git a/clang/test/AST/HLSL/RootSignatures-AST.hlsl b/clang/test/AST/HLSL/RootSignatures-AST.hlsl new file mode 100644 index 0000000000000..c700174da764d --- /dev/null +++ b/clang/test/AST/HLSL/RootSignatures-AST.hlsl @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -ast-dump \ +// RUN: -disable-llvm-passes -o - %s | FileCheck %s + +// This test ensures that the sample root signature is parsed without error and +// the Attr AST Node is created succesfully. If an invalid root signature was +// passed in then we would exit out of Sema before the Attr is created. + +#define SampleRS \ + "DescriptorTable( " \ + " CBV(b1), " \ + " SRV(t1, numDescriptors = 8, " \ + " flags = DESCRIPTORS_VOLATILE), " \ + " UAV(u1, numDescriptors = 0, " \ + " flags = DESCRIPTORS_VOLATILE) " \ + "), " \ + "DescriptorTable(Sampler(s0, numDescriptors = 4, space = 1))" + +// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[SAMPLE_RS_DECL:__hlsl_rootsig_decl_\d*]] +// CHECK-SAME: RootElements{ +// CHECK-SAME: CBV(b1, numDescriptors = 1, space = 0, +// CHECK-SAME: offset = DescriptorTableOffsetAppend, flags = DataStaticWhileSetAtExecute), +// CHECK-SAME: SRV(t1, numDescriptors = 8, space = 0, +// CHECK-SAME: offset = DescriptorTableOffsetAppend, flags = DescriptorsVolatile), +// CHECK-SAME: UAV(u1, numDescriptors = 0, space = 0, +// CHECK-SAME: offset = DescriptorTableOffsetAppend, flags = DescriptorsVolatile), +// CHECK-SAME: DescriptorTable(numClauses = 3, visibility = All), +// CHECK-SAME: Sampler(s0, numDescriptors = 4, space = 1, +// CHECK-SAME: offset = DescriptorTableOffsetAppend, flags = None), +// CHECK-SAME: DescriptorTable(numClauses = 1, visibility = All) +// CHECK-SAME: } + +// CHECK: -RootSignatureAttr 0x{{.*}} {{.*}} [[SAMPLE_RS_DECL]] +[RootSignature(SampleRS)] +void rs_main() {} + +// Ensure that if multiple root signatures are specified at diff erent entry +// points that we point to the correct root signature + +// CHECK: -RootSignatureAttr 0x{{.*}} {{.*}} [[SAMPLE_RS_DECL]] +[RootSignature(SampleRS)] +void same_rs_main() {} + +// Define the same root signature to ensure that the entry point will still +// link to the same root signature declaration + +#define SampleSameRS \ + "DescriptorTable( " \ + " CBV(b1), " \ + " SRV(t1, numDescriptors = 8, " \ + " flags = DESCRIPTORS_VOLATILE), " \ + " UAV(u1, numDescriptors = 0, " \ + " flags = DESCRIPTORS_VOLATILE) " \ + "), " \ + "DescriptorTable(Sampler(s0, numDescriptors = 4, space = 1))" + +// CHECK: -RootSignatureAttr 0x{{.*}} {{.*}} [[SAMPLE_RS_DECL]] +[RootSignature(SampleSameRS)] +void same_rs_string_main() {} + +#define SampleDifferentRS \ + "DescriptorTable(Sampler(s0, numDescriptors = 4, space = 1))" + +// Ensure that when we define a diff erent type root signature that it creates +// a seperate decl and identifier to reference + +// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[DIFF_RS_DECL:__hlsl_rootsig_decl_\d*]] +// CHECK-SAME: RootElements{ +// CHECK-SAME: Sampler(s0, numDescriptors = 4, space = 1, +// CHECK-SAME: offset = DescriptorTableOffsetAppend, flags = None), +// CHECK-SAME: DescriptorTable(numClauses = 1, visibility = All) +// CHECK-SAME: } + +// CHECK: -RootSignatureAttr 0x{{.*}} {{.*}} [[DIFF_RS_DECL]] +[RootSignature(SampleDifferentRS)] +void diff erent_rs_string_main() {} diff --git a/clang/test/SemaHLSL/RootSignature-err.hlsl b/clang/test/SemaHLSL/RootSignature-err.hlsl new file mode 100644 index 0000000000000..f544247f4db2a --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-err.hlsl @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify + +// Attr test + +[RootSignature()] // expected-error {{expected string literal as argument of 'RootSignature' attribute}} +void bad_root_signature_0() {} + +// expected-error@+2 {{expected ')'}} +// expected-note@+1 {{to match this '('}} +[RootSignature("", "")] +void bad_root_signature_1() {} + +[RootSignature(""), RootSignature("DescriptorTable()")] // expected-error {{attribute 'RootSignature' cannot appear more than once on a declaration}} +void bad_root_signature_2() {} + +[RootSignature(""), RootSignature("")] // expected-warning {{attribute 'RootSignature' is already applied}} +void bad_root_signature_3() {} + +[RootSignature("DescriptorTable(), invalid")] // expected-error {{expected end of stream to denote end of parameters, or, another valid parameter of RootSignature}} +void bad_root_signature_4() {} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 42c24cb9b6e50..9163c87ea7717 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7229,6 +7229,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::MSProperty: case Decl::MSGuid: case Decl::HLSLBuffer: + case Decl::HLSLRootSignature: case Decl::UnnamedGlobalConstant: case Decl::TemplateParamObject: case Decl::IndirectField: diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h index be0ec5d072ed0..37f3d9ad61d3e 100644 --- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h @@ -14,6 +14,7 @@ #ifndef LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H #define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/raw_ostream.h" #include <variant> @@ -122,6 +123,8 @@ struct DescriptorTableClause { using RootElement = std::variant<RootFlags, RootConstants, DescriptorTable, DescriptorTableClause>; +void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements); + } // namespace rootsig } // namespace hlsl } // namespace llvm diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp index 5351239b94b1e..cd3c6f8dde8be 100644 --- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp +++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp @@ -144,6 +144,22 @@ void DescriptorTableClause::dump(raw_ostream &OS) const { OS << ", flags = " << Flags << ")"; } +void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) { + OS << "RootElements{"; + bool First = true; + for (const RootElement &Element : Elements) { + if (!First) + OS << ","; + OS << " "; + First = false; + if (const auto &Clause = std::get_if<DescriptorTableClause>(&Element)) + Clause->dump(OS); + if (const auto &Table = std::get_if<DescriptorTable>(&Element)) + Table->dump(OS); + } + OS << "}"; +} + } // namespace rootsig } // namespace hlsl } // namespace llvm _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits