[llvm-branch-commits] [clang] [llvm] [HLSL][RootSignature] Define and integrate rootsig clang attr and decl (PR #137690)
Finn Plummer via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri May 2 12:55:40 PDT 2025
https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/137690
>From 0ccff5b9be4f876969e4db439e67edbc7af6cb29 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Mon, 28 Apr 2025 18:42:10 +0000
Subject: [PATCH 01/13] [HLSL][RootSignature] Define and integrate rootsig
clang attr and decl
- Defines a new declaration node `HLSLRootSignature` in `DeclNodes.td`
that will hold a reference to an 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 declration as above
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 seperate root signature decl. In contrast, by defining
them seperately 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 rootsignature
attributes. Having it located directly as a declaration might also prove
advantageous when we consider root signature libraries.
---
clang/include/clang/AST/Decl.h | 24 +++++
clang/include/clang/AST/RecursiveASTVisitor.h | 2 +
clang/include/clang/AST/TextNodeDumper.h | 1 +
clang/include/clang/Basic/Attr.td | 11 +++
clang/include/clang/Basic/AttrDocs.td | 11 +++
clang/include/clang/Basic/DeclNodes.td | 1 +
clang/include/clang/Parse/Parser.h | 1 +
clang/include/clang/Sema/SemaHLSL.h | 1 +
clang/lib/AST/Decl.cpp | 25 ++++++
clang/lib/AST/DeclBase.cpp | 1 +
clang/lib/AST/TextNodeDumper.cpp | 4 +
clang/lib/CodeGen/CGDecl.cpp | 1 +
clang/lib/Parse/ParseDeclCXX.cpp | 90 +++++++++++++++++++
clang/lib/Sema/SemaDeclAttr.cpp | 3 +
clang/lib/Sema/SemaHLSL.cpp | 18 ++++
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 ++
clang/lib/Serialization/ASTCommon.cpp | 1 +
clang/test/AST/HLSL/RootSignatures-AST.hlsl | 58 ++++++++++++
clang/test/SemaHLSL/RootSignature-err.hlsl | 11 +++
clang/tools/libclang/CIndex.cpp | 1 +
20 files changed, 270 insertions(+)
create mode 100644 clang/test/AST/HLSL/RootSignatures-AST.hlsl
create mode 100644 clang/test/SemaHLSL/RootSignature-err.hlsl
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 3faf63e395a08..8e45c19061b1d 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,29 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
friend class ASTDeclWriter;
};
+class HLSLRootSignatureDecl final : public NamedDecl {
+ ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements;
+
+ HLSLRootSignatureDecl(
+ DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID,
+ ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements);
+
+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() {
+ return RootElements;
+ }
+
+ // 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 d48aed5b73cf5..81b411e8f8d01 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4698,6 +4698,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 98468034e71a8..adf4e0624a657 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8184,6 +8184,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 645df4aabc374..1c1092b49a142 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3070,6 +3070,7 @@ class Parser : public CodeCompletionHandler {
}
}
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 e97736b18eee3..bfcbfebdd49d7 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -118,6 +118,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/Decl.cpp b/clang/lib/AST/Decl.cpp
index 1d9208f0e1c72..4dd3f53f430ce 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5839,6 +5839,31 @@ bool HLSLBufferDecl::buffer_decls_empty() {
return DefaultBufferDecls.empty() && decls_empty();
}
+//===----------------------------------------------------------------------===//
+// HLSLRootSignatureDecl Implementation
+//===----------------------------------------------------------------------===//
+
+HLSLRootSignatureDecl::HLSLRootSignatureDecl(
+ DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID,
+ ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements)
+ : NamedDecl(Decl::Kind::HLSLRootSignature, DC, Loc, DeclarationName(ID)),
+ RootElements(RootElements) {}
+
+HLSLRootSignatureDecl *HLSLRootSignatureDecl::Create(
+ ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID,
+ ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements) {
+ HLSLRootSignatureDecl *Result =
+ new (C, DC) HLSLRootSignatureDecl(DC, Loc, ID, RootElements);
+ return Result;
+}
+
+HLSLRootSignatureDecl *
+HLSLRootSignatureDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
+ HLSLRootSignatureDecl *Result =
+ new (C, ID) HLSLRootSignatureDecl(nullptr, SourceLocation(), nullptr, {});
+ return Result;
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 1afda9aac9e18..abca645cdd6af 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -882,6 +882,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 51f7d17be4158..8263bbc992fc0 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -3037,6 +3037,10 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
dumpName(D);
}
+void TextNodeDumper::VisitHLSLRootSignatureDecl(const HLSLRootSignatureDecl *D) {
+ dumpName(D);
+}
+
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 db34e2738b4cf..e93e35a9d585f 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 51fe0663a8d1a..6d594af54aed6 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"
@@ -5209,6 +5211,92 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) {
}
}
+void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
+ assert(Tok.is(tok::identifier) && "Not a Microsoft attribute list");
+ IdentifierInfo *RootSignatureIdent = Tok.getIdentifierInfo();
+ assert(RootSignatureIdent->getName() == "RootSignature" &&
+ "Not a Microsoft attribute list");
+
+ 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;
+ }
+
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*in attributes...*/ 4 << RootSignatureIdent->getName();
+ SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+ if (Tok.is(tok::r_paren))
+ T.consumeClose();
+ return;
+ }
+
+ ExprResult StringResult = ParseUnevaluatedStringLiteralExpression();
+ if (StringResult.isInvalid()) {
+ SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+ if (Tok.is(tok::r_paren))
+ T.consumeClose();
+ return;
+ }
+
+ ArgsVector Args;
+ if (auto Lit = dyn_cast<StringLiteral>(StringResult.get())) {
+ // Construct our identifier
+ StringRef Signature = Lit->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)) {
+ // Invoke the root signature parser to construct the in-memory constructs
+ hlsl::RootSignatureLexer Lexer(Signature, RootSignatureLoc);
+ SmallVector<llvm::hlsl::rootsig::RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, PP);
+ if (Parser.parse()) {
+ SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+ if (Tok.is(tok::r_paren))
+ T.consumeClose();
+ return;
+ }
+
+ // Allocate the root elements onto ASTContext
+ unsigned N = Elements.size();
+ auto RootElements = MutableArrayRef<llvm::hlsl::rootsig::RootElement>(
+ ::new (Actions.getASTContext()) llvm::hlsl::rootsig::RootElement[N],
+ N);
+ for (unsigned I = 0; I < N; ++I)
+ RootElements[I] = Elements[I];
+
+ // Create the Root Signature
+ auto *SignatureDecl = HLSLRootSignatureDecl::Create(
+ Actions.getASTContext(), /*FIXME?*/ 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);
+ Args.push_back(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:
@@ -5243,6 +5331,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 c960868badb52..8c44c1a4a6a06 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7461,6 +7461,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 38322e6ba063b..353217961121c 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"
@@ -949,6 +950,23 @@ 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();
+ 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 76c055d28f091..9d70d06451e48 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 320ee0e65dbea..480ce78e6b08b 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..e6ed27b62588a
--- /dev/null
+++ b/clang/test/AST/HLSL/RootSignatures-AST.hlsl
@@ -0,0 +1,58 @@
+// 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_.*]]
+
+// 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_.*]]
+
+// 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..6427c78b38455
--- /dev/null
+++ b/clang/test/SemaHLSL/RootSignature-err.hlsl
@@ -0,0 +1,11 @@
+// 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 at +2 {{expected ')'}}
+// expected-note at +1 {{to match this '('}}
+[RootSignature("", "")]
+void bad_root_signature_1() {}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 809000a5086b1..d1f66158b3621 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:
>From a54098ea0dd191b24c8bd5187a921fabe1d5a3fc Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Mon, 28 Apr 2025 19:08:12 +0000
Subject: [PATCH 02/13] clang format
---
clang/lib/AST/TextNodeDumper.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 8263bbc992fc0..7cc7637a4fe27 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -3037,7 +3037,8 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
dumpName(D);
}
-void TextNodeDumper::VisitHLSLRootSignatureDecl(const HLSLRootSignatureDecl *D) {
+void TextNodeDumper::VisitHLSLRootSignatureDecl(
+ const HLSLRootSignatureDecl *D) {
dumpName(D);
}
>From 9fe54eafcbc70d2aec93bc6c0b55e788c93b04e5 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 18:29:57 +0000
Subject: [PATCH 03/13] review: improve assert messages
---
clang/lib/Parse/ParseDeclCXX.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 6d594af54aed6..8337b7322f553 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5212,10 +5212,11 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) {
}
void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
- assert(Tok.is(tok::identifier) && "Not a Microsoft attribute list");
+ assert(Tok.is(tok::identifier) &&
+ "Expected an identifier to denote which MS attribute to consider");
IdentifierInfo *RootSignatureIdent = Tok.getIdentifierInfo();
assert(RootSignatureIdent->getName() == "RootSignature" &&
- "Not a Microsoft attribute list");
+ "Expected RootSignature identifier for root signature attribute");
SourceLocation RootSignatureLoc = Tok.getLocation();
ConsumeToken();
>From 27728c28d6ef71b2764c1ca8c1a4b80eedc6c650 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 18:33:17 +0000
Subject: [PATCH 04/13] review: remove FIXME
- this is correct as we do want to add the newly constructed Declaration
into the current decl context, such that we can retrieve it later when
we look it up from the function declaration in the same context
---
clang/lib/Parse/ParseDeclCXX.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8337b7322f553..d26700fecbd69 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5279,7 +5279,7 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
// Create the Root Signature
auto *SignatureDecl = HLSLRootSignatureDecl::Create(
- Actions.getASTContext(), /*FIXME?*/ Actions.CurContext,
+ Actions.getASTContext(), /*DeclContext=*/Actions.CurContext,
RootSignatureLoc, DeclIdent, RootElements);
SignatureDecl->setImplicit();
Actions.PushOnScopeChains(SignatureDecl, getCurScope());
>From 118bf036794671a9c09aebcf77301673a66710be Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 18:48:12 +0000
Subject: [PATCH 05/13] review: unify error reporting of having an invalid
string literal argument
---
clang/lib/Parse/ParseDeclCXX.cpp | 107 ++++++++++++++++---------------
1 file changed, 56 insertions(+), 51 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d26700fecbd69..c4db9c81d5518 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5228,7 +5228,22 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
return;
}
- if (!isTokenStringLiteral()) {
+ 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_square, StopAtSemi | StopBeforeMatch);
@@ -5236,60 +5251,50 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
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)) {
+ // Invoke the root signature parser to construct the in-memory constructs
+ hlsl::RootSignatureLexer Lexer(Signature, RootSignatureLoc);
+ SmallVector<llvm::hlsl::rootsig::RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, PP);
+ if (Parser.parse()) {
+ SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+ if (Tok.is(tok::r_paren))
+ T.consumeClose();
+ return;
+ }
- ExprResult StringResult = ParseUnevaluatedStringLiteralExpression();
- if (StringResult.isInvalid()) {
- SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::r_paren))
- T.consumeClose();
- return;
- }
+ // Allocate the root elements onto ASTContext
+ unsigned N = Elements.size();
+ auto RootElements = MutableArrayRef<llvm::hlsl::rootsig::RootElement>(
+ ::new (Actions.getASTContext()) llvm::hlsl::rootsig::RootElement[N],
+ N);
+ for (unsigned I = 0; I < N; ++I)
+ RootElements[I] = Elements[I];
- ArgsVector Args;
- if (auto Lit = dyn_cast<StringLiteral>(StringResult.get())) {
- // Construct our identifier
- StringRef Signature = Lit->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)) {
- // Invoke the root signature parser to construct the in-memory constructs
- hlsl::RootSignatureLexer Lexer(Signature, RootSignatureLoc);
- SmallVector<llvm::hlsl::rootsig::RootElement> Elements;
- hlsl::RootSignatureParser Parser(Elements, Lexer, PP);
- if (Parser.parse()) {
- SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::r_paren))
- 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());
+ }
- // Allocate the root elements onto ASTContext
- unsigned N = Elements.size();
- auto RootElements = MutableArrayRef<llvm::hlsl::rootsig::RootElement>(
- ::new (Actions.getASTContext()) llvm::hlsl::rootsig::RootElement[N],
- N);
- for (unsigned I = 0; I < N; ++I)
- RootElements[I] = Elements[I];
-
- // 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);
- // Create the arg for the ParsedAttr
- IdentifierLoc *ILoc = ::new (Actions.getASTContext())
- IdentifierLoc(RootSignatureLoc, DeclIdent);
- Args.push_back(ILoc);
- }
+ ArgsVector Args = { ILoc };
if (!T.consumeClose())
Attrs.addNew(RootSignatureIdent,
>From b4a074eea6616ed739d0f8ec5cfd970f2a418b89 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 18:48:41 +0000
Subject: [PATCH 06/13] clang-format
---
clang/lib/Parse/ParseDeclCXX.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index c4db9c81d5518..9afacb400347d 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5235,7 +5235,7 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
ExprResult StringResult = ParseUnevaluatedStringLiteralExpression();
if (StringResult.isInvalid())
return std::nullopt;
-
+
if (auto Lit = dyn_cast<StringLiteral>(StringResult.get()))
return Lit;
@@ -5251,7 +5251,7 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
T.consumeClose();
return;
}
-
+
// Construct our identifier
StringRef Signature = StrLiteral.value()->getString();
auto Hash = llvm::hash_value(Signature);
@@ -5277,8 +5277,7 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
// Allocate the root elements onto ASTContext
unsigned N = Elements.size();
auto RootElements = MutableArrayRef<llvm::hlsl::rootsig::RootElement>(
- ::new (Actions.getASTContext()) llvm::hlsl::rootsig::RootElement[N],
- N);
+ ::new (Actions.getASTContext()) llvm::hlsl::rootsig::RootElement[N], N);
for (unsigned I = 0; I < N; ++I)
RootElements[I] = Elements[I];
@@ -5294,7 +5293,7 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
IdentifierLoc *ILoc = ::new (Actions.getASTContext())
IdentifierLoc(RootSignatureLoc, DeclIdent);
- ArgsVector Args = { ILoc };
+ ArgsVector Args = {ILoc};
if (!T.consumeClose())
Attrs.addNew(RootSignatureIdent,
>From f5e71a6d4444c3f0cdc3a9258488cf88bf1376fc Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 19:10:19 +0000
Subject: [PATCH 07/13] review: use TrailingObjects to store elements instead
of on the context
---
clang/include/clang/AST/Decl.h | 27 ++++++++++++++++++++-------
clang/lib/AST/Decl.cpp | 25 ++++++++++++++++---------
2 files changed, 36 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 8e45c19061b1d..f1013c57e008f 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5179,22 +5179,35 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext {
friend class ASTDeclWriter;
};
-class HLSLRootSignatureDecl final : public NamedDecl {
- ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements;
+class HLSLRootSignatureDecl final
+ : public NamedDecl,
+ private llvm::TrailingObjects<HLSLRootSignatureDecl,
+ llvm::hlsl::rootsig::RootElement> {
+ friend TrailingObjects;
+
+ unsigned NumElems;
- HLSLRootSignatureDecl(
- DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID,
- ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements);
+ 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() {
- return RootElements;
+ ArrayRef<llvm::hlsl::rootsig::RootElement> getRootElements() const {
+ return {getElems(), NumElems};
}
// Implement isa/cast/dyncast/etc.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 4dd3f53f430ce..ee52c859fbbfd 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5843,24 +5843,31 @@ bool HLSLBufferDecl::buffer_decls_empty() {
// HLSLRootSignatureDecl Implementation
//===----------------------------------------------------------------------===//
-HLSLRootSignatureDecl::HLSLRootSignatureDecl(
- DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID,
- ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements)
+HLSLRootSignatureDecl::HLSLRootSignatureDecl(DeclContext *DC,
+ SourceLocation Loc,
+ IdentifierInfo *ID,
+ unsigned NumElems)
: NamedDecl(Decl::Kind::HLSLRootSignature, DC, Loc, DeclarationName(ID)),
- RootElements(RootElements) {}
+ NumElems(NumElems) {}
HLSLRootSignatureDecl *HLSLRootSignatureDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation Loc, IdentifierInfo *ID,
ArrayRef<llvm::hlsl::rootsig::RootElement> RootElements) {
- HLSLRootSignatureDecl *Result =
- new (C, DC) HLSLRootSignatureDecl(DC, Loc, ID, RootElements);
- return Result;
+ 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, {});
+ HLSLRootSignatureDecl *Result = new (C, ID)
+ HLSLRootSignatureDecl(nullptr, SourceLocation(), nullptr, /*NumElems=*/0);
return Result;
}
>From 70d6580cb1fdaec90beaf71f6dc7b1c14428cecb Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 21:10:08 +0000
Subject: [PATCH 08/13] review: update duplicate attrs warning/error
---
clang/lib/Sema/SemaHLSL.cpp | 10 ++++++++++
clang/test/SemaHLSL/RootSignature-err.hlsl | 6 ++++++
2 files changed, 16 insertions(+)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 353217961121c..0358e192f76c8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -957,6 +957,16 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
}
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 =
diff --git a/clang/test/SemaHLSL/RootSignature-err.hlsl b/clang/test/SemaHLSL/RootSignature-err.hlsl
index 6427c78b38455..21af0a6552bbc 100644
--- a/clang/test/SemaHLSL/RootSignature-err.hlsl
+++ b/clang/test/SemaHLSL/RootSignature-err.hlsl
@@ -9,3 +9,9 @@ void bad_root_signature_0() {}
// expected-note at +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() {}
>From 4908ecff5950b94cccc327446cdcb14b895fbca7 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 22:39:35 +0000
Subject: [PATCH 09/13] self-review: correct retrieved start location
- increment the location by one to better point past the initial "
character of a string literal
- add test that demonstrates an HLSLRootSignature parsing error being
propogated up and it correctly continues parsing after the closed paren
enclosing the string literal
---
clang/lib/Parse/ParseDeclCXX.cpp | 4 +++-
clang/test/SemaHLSL/RootSignature-err.hlsl | 3 +++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 9afacb400347d..7ecc64929d124 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5263,8 +5263,10 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
// 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, RootSignatureLoc);
+ hlsl::RootSignatureLexer Lexer(Signature, SignatureLoc);
SmallVector<llvm::hlsl::rootsig::RootElement> Elements;
hlsl::RootSignatureParser Parser(Elements, Lexer, PP);
if (Parser.parse()) {
diff --git a/clang/test/SemaHLSL/RootSignature-err.hlsl b/clang/test/SemaHLSL/RootSignature-err.hlsl
index 21af0a6552bbc..f544247f4db2a 100644
--- a/clang/test/SemaHLSL/RootSignature-err.hlsl
+++ b/clang/test/SemaHLSL/RootSignature-err.hlsl
@@ -15,3 +15,6 @@ 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() {}
>From 73c8af5dccca097437ed597384ccb85693aad1e6 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 30 Apr 2025 22:40:26 +0000
Subject: [PATCH 10/13] self-review: update skip logic to account for context
---
clang/lib/Parse/ParseDeclCXX.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 7ecc64929d124..40a6c8a9ed5bd 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5246,9 +5246,8 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
if (!StrLiteral.has_value()) {
Diag(Tok, diag::err_expected_string_literal)
<< /*in attributes...*/ 4 << RootSignatureIdent->getName();
- SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::r_paren))
- T.consumeClose();
+ SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
+ T.consumeClose();
return;
}
@@ -5270,9 +5269,7 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
SmallVector<llvm::hlsl::rootsig::RootElement> Elements;
hlsl::RootSignatureParser Parser(Elements, Lexer, PP);
if (Parser.parse()) {
- SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::r_paren))
- T.consumeClose();
+ T.consumeClose();
return;
}
>From a62c4eb430e4dd3971fb1ed3ae1eccd1e06b4489 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Thu, 1 May 2025 00:02:40 +0000
Subject: [PATCH 11/13] clang-format
---
clang/lib/Parse/ParseDeclCXX.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 40a6c8a9ed5bd..79a102ad0c1f9 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5263,7 +5263,8 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
// 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 '"'
+ 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> Elements;
>From 57f60c396cff0c69e8333208b9f9562c15dba3c7 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Fri, 2 May 2025 19:49:20 +0000
Subject: [PATCH 12/13] rebase: hook-up root elements to invoke there dump
- update ast test to ensure elements are correctly allocated
---
clang/lib/AST/CMakeLists.txt | 1 +
clang/lib/AST/TextNodeDumper.cpp | 2 ++
clang/test/AST/HLSL/RootSignatures-AST.hlsl | 21 +++++++++++++--
.../llvm/Frontend/HLSL/HLSLRootSignature.h | 3 +++
llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp | 27 +++++++++++++++++++
5 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index f6056e3935a63..b54b4d1b1d6f5 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/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 7cc7637a4fe27..2d9aef6ca0561 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>
@@ -3040,6 +3041,7 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
void TextNodeDumper::VisitHLSLRootSignatureDecl(
const HLSLRootSignatureDecl *D) {
dumpName(D);
+ llvm::hlsl::rootsig::dumpRootElements(OS, D->getRootElements());
}
void TextNodeDumper::VisitHLSLOutArgExpr(const HLSLOutArgExpr *E) {
diff --git a/clang/test/AST/HLSL/RootSignatures-AST.hlsl b/clang/test/AST/HLSL/RootSignatures-AST.hlsl
index e6ed27b62588a..c700174da764d 100644
--- a/clang/test/AST/HLSL/RootSignatures-AST.hlsl
+++ b/clang/test/AST/HLSL/RootSignatures-AST.hlsl
@@ -15,7 +15,19 @@
"), " \
"DescriptorTable(Sampler(s0, numDescriptors = 4, space = 1))"
-// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[SAMPLE_RS_DECL:__hlsl_rootsig_decl_.*]]
+// 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)]
@@ -51,7 +63,12 @@ void same_rs_string_main() {}
// 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_.*]]
+// 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)]
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 6d3ecd166f461..d54fbb0075f62 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>
@@ -98,6 +99,8 @@ struct DescriptorTableClause {
// Models RootElement : DescriptorTable | DescriptorTableClause
using RootElement = std::variant<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 a5f0313138521..63c4eab245631 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -149,6 +149,33 @@ void DescriptorTableClause::dump(raw_ostream &OS) const {
OS << ")";
}
+// Helper struct so that we can use the overloaded notation of std::visit
+template <class... Ts> struct OverloadMethods : Ts... {
+ using Ts::operator()...;
+};
+
+template <class... Ts> OverloadMethods(Ts...) -> OverloadMethods<Ts...>;
+
+void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
+ OS << "RootElements{";
+ bool First = true;
+ for (auto Element : Elements) {
+ if (!First)
+ OS << ",";
+ OS << " ";
+ First = false;
+ std::visit(OverloadMethods{
+ [&OS](DescriptorTable Table) {
+ Table.dump(OS);
+ },
+ [&OS](DescriptorTableClause Clause) {
+ Clause.dump(OS);
+ }
+ }, Element);
+ }
+ OS << "}";
+}
+
} // namespace rootsig
} // namespace hlsl
} // namespace llvm
>From 8690bb34ab4faa6f5b3f1a33485c643d0c7921c8 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Fri, 2 May 2025 19:49:48 +0000
Subject: [PATCH 13/13] self-review: remove ast allocation
---
clang/lib/Parse/ParseDeclCXX.cpp | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 79a102ad0c1f9..e3646d291660b 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -5267,20 +5267,13 @@ void Parser::ParseMicrosoftRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
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> Elements;
- hlsl::RootSignatureParser Parser(Elements, Lexer, PP);
+ SmallVector<llvm::hlsl::rootsig::RootElement> RootElements;
+ hlsl::RootSignatureParser Parser(RootElements, Lexer, PP);
if (Parser.parse()) {
T.consumeClose();
return;
}
- // Allocate the root elements onto ASTContext
- unsigned N = Elements.size();
- auto RootElements = MutableArrayRef<llvm::hlsl::rootsig::RootElement>(
- ::new (Actions.getASTContext()) llvm::hlsl::rootsig::RootElement[N], N);
- for (unsigned I = 0; I < N; ++I)
- RootElements[I] = Elements[I];
-
// Create the Root Signature
auto *SignatureDecl = HLSLRootSignatureDecl::Create(
Actions.getASTContext(), /*DeclContext=*/Actions.CurContext,
More information about the llvm-branch-commits
mailing list