diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 3365ebe4d9012..d45b8891cf1a7 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -26,6 +26,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Support/Compiler.h" #include "llvm/Frontend/HLSL/HLSLResource.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/VersionTuple.h" diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 52ad72eb608c3..094aba5f6fadc 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4643,6 +4643,26 @@ def Error : InheritableAttr { let Documentation = [ErrorAttrDocs]; } +/// HLSL Root Signature Attribute +def HLSLRootSignature : Attr { + /// [RootSignature(Signature)] + let Spellings = [Microsoft<"RootSignature">]; + let Args = [StringArgument<"Signature">]; + let Subjects = SubjectList<[Function], + ErrorDiag, "'function'">; + let LangOpts = [HLSL]; + let Documentation = [HLSLRootSignatureDocs]; + let AdditionalMembers = [{ +private: + ArrayRef RootElements; +public: + void setElements(ArrayRef Elements) { + RootElements = Elements; + } + auto getElements() const { return RootElements; } +}]; +} + 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 fdad4c9a3ea19..dc909cf0ae9b7 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7783,6 +7783,17 @@ and https://microsoft.github.io/hlsl-specs/proposals/0013-wave-size-range.html }]; } +def HLSLRootSignatureDocs : 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/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index f4cd11f423a84..df4a5c8d88ba9 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -116,6 +116,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/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index bb4d33560b93b..c594d6e54ddbc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7149,6 +7149,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, break; // HLSL attributes: + case ParsedAttr::AT_HLSLRootSignature: + 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 600c800029fd0..02f2faf108578 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Parse/ParseHLSLRootSignature.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" @@ -647,6 +648,38 @@ 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; + } + + StringRef Signature; + if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Signature)) + return; + + SourceLocation Loc = AL.getArgAsExpr(0)->getExprLoc(); + // TODO(#126565): pass down below to lexer when fp is supported + // llvm::RoundingMode RM = SemaRef.CurFPFeatures.getRoundingMode(); + hlsl::RootSignatureLexer Lexer(Signature, Loc, SemaRef.getPreprocessor()); + SmallVector Elements; + hlsl::RootSignatureParser Parser(Elements, Lexer, + SemaRef.getPreprocessor().getDiagnostics()); + if (Parser.Parse()) + return; + + unsigned N = Elements.size(); + auto RootElements = MutableArrayRef( + ::new (getASTContext()) llvm::hlsl::rootsig::RootElement[N], N); + for (unsigned I = 0; I < N; ++I) + RootElements[I] = Elements[I]; + + auto *Result = ::new (getASTContext()) + HLSLRootSignatureAttr(getASTContext(), AL, Signature); + Result->setElements(ArrayRef(RootElements)); + D->addAttr(Result); +} + void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { llvm::VersionTuple SMVersion = getASTContext().getTargetInfo().getTriple().getOSVersion(); diff --git a/clang/test/AST/HLSL/RootSignatures-AST.hlsl b/clang/test/AST/HLSL/RootSignatures-AST.hlsl new file mode 100644 index 0000000000000..9b0908c053254 --- /dev/null +++ b/clang/test/AST/HLSL/RootSignatures-AST.hlsl @@ -0,0 +1,28 @@ +// 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: HLSLRootSignatureAttr +// CHECK-SAME: "DescriptorTable( +// CHECK-SAME: CBV(b1), +// CHECK-SAME: SRV(t1, numDescriptors = 8, +// CHECK-SAME: flags = DESCRIPTORS_VOLATILE), +// CHECK-SAME: UAV(u1, numDescriptors = 0, +// CHECK-SAME: flags = DESCRIPTORS_VOLATILE) +// CHECK-SAME: ), +// CHECK-SAME: DescriptorTable(Sampler(s0, numDescriptors = 4, space = 1))" +[RootSignature(SampleRS)] +void main() {} diff --git a/clang/test/SemaHLSL/RootSignature-err.hlsl b/clang/test/SemaHLSL/RootSignature-err.hlsl new file mode 100644 index 0000000000000..6e868e06773c8 --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-err.hlsl @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify + +// This file mirrors the diagnostics testing in ParseHLSLRootSignatureTest.cpp +// to verify that the correct diagnostics strings are output + +// Attr test + +[RootSignature()] // expected-error {{'RootSignature' attribute takes one argument}} +void bad_root_signature_0() {} + +// Lexer related tests + +#define InvalidToken \ + "DescriptorTable( " \ + " invalid " \ + ")" + +[RootSignature(InvalidToken)] // expected-error {{expected one of the following token kinds: CBV, SRV, UAV, Sampler}} +void bad_root_signature_1() {} + +#define InvalidEmptyNumber \ + "DescriptorTable( " \ + " CBV(t32, space = +) " \ + ")" + +// expected-error@+1 {{expected the following token kind: integer literal}} +[RootSignature(InvalidEmptyNumber)] +void bad_root_signature_2() {} + +#define InvalidOverflowNumber \ + "DescriptorTable( " \ + " CBV(t32, space = 98273498327498273487) " \ + ")" + +// expected-error@+1 {{integer literal '98273498327498273487' is too large to be represented in a 32-bit integer type}} +[RootSignature(InvalidOverflowNumber)] +void bad_root_signature_3() {} + +// Parser related tests + +#define InvalidEOS \ + "DescriptorTable( " \ + " CBV(" + +[RootSignature(InvalidEOS)] // expected-error {{expected one of the following token kinds: b register, t register, u register, s register}} +void bad_root_signature_4() {} + +#define InvalidTokenKind \ + "DescriptorTable( " \ + " SRV(s0, CBV())" \ + ")" + +[RootSignature(InvalidTokenKind)] // expected-error {{expected one of the following token kinds: offset, numDescriptors, space, flags}} +void bad_root_signature_5() {} + +#define InvalidRepeat \ + "DescriptorTable( " \ + " CBV(t0, space = 1, space = 2)" \ + ")" + +[RootSignature(InvalidRepeat)] // expected-error {{specified the same parameter 'space' multiple times}} +void bad_root_signature_6() {}