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 { + friend TrailingObjects; + + unsigned NumElems; + + llvm::hlsl::rootsig::RootElement *getElems() { + return getTrailingObjects(); + } + + const llvm::hlsl::rootsig::RootElement *getElems() const { + return getTrailingObjects(); + } + + HLSLRootSignatureDecl(DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, + unsigned NumElems); + +public: + static HLSLRootSignatureDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID, + ArrayRef RootElements); + + static HLSLRootSignatureDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); + + ArrayRef 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; def RequiresExprBody : DeclNode, DeclContext; def LifetimeExtendedTemporary : DeclNode; def HLSLBuffer : DeclNode, DeclContext; +def HLSLRootSignature : DeclNode; def OpenACCDeclare : DeclNode; def OpenACCRoutine : DeclNode; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index d2fec2b7a6462..cab56f9edbcf1 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 RootElements) { + HLSLRootSignatureDecl *RSDecl = + new (C, DC, + additionalSizeToAlloc( + 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 #include @@ -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 { + if (!isTokenStringLiteral()) + return std::nullopt; + + ExprResult StringResult = ParseUnevaluatedStringLiteralExpression(); + if (StringResult.isInvalid()) + return std::nullopt; + + if (auto Lit = dyn_cast(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 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()) { + 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(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 different 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 different 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 different_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 fa5df3b5a06e6..43ac6880ca1da 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7230,6 +7230,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 @@ -122,6 +123,8 @@ struct DescriptorTableClause { using RootElement = std::variant; +void dumpRootElements(raw_ostream &OS, ArrayRef 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 Elements) { + OS << "RootElements{"; + bool First = true; + for (const RootElement &Element : Elements) { + if (!First) + OS << ","; + OS << " "; + First = false; + if (const auto &Clause = std::get_if(&Element)) + Clause->dump(OS); + if (const auto &Table = std::get_if(&Element)) + Table->dump(OS); + } + OS << "}"; +} + } // namespace rootsig } // namespace hlsl } // namespace llvm