https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/156373
>From 1ff0888cb712c69f5fe6f587b60649d03b0472cd Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Fri, 29 Aug 2025 09:42:59 -0700 Subject: [PATCH 01/17] add support for rootsig as an hlsl environment --- clang/include/clang/Basic/Attr.td | 1 + clang/include/clang/Driver/Options.td | 3 ++- clang/lib/Driver/ToolChains/HLSL.cpp | 5 +++++ clang/lib/Sema/SemaHLSL.cpp | 4 ++++ llvm/include/llvm/TargetParser/Triple.h | 3 ++- llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp | 2 ++ llvm/lib/TargetParser/Triple.cpp | 3 +++ 7 files changed, 19 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 0fb0e7178404e..00d959651b58b 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1185,6 +1185,7 @@ static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environm .Case("callable", llvm::Triple::Callable) .Case("mesh", llvm::Triple::Mesh) .Case("amplification", llvm::Triple::Amplification) + .Case("rootsignature", llvm::Triple::RootSignature) .Case("library", llvm::Triple::Library) .Default(llvm::Triple::UnknownEnvironment); } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 718808d583e8c..29c966e706aca 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -9432,7 +9432,8 @@ def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">, "cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, cs_6_7," "lib_6_3, lib_6_4, lib_6_5, lib_6_6, lib_6_7, lib_6_x," "ms_6_5, ms_6_6, ms_6_7," - "as_6_5, as_6_6, as_6_7">; + "as_6_5, as_6_6, as_6_7," + "rootsig_1_0, rootsig_1_1">; def emit_pristine_llvm : DXCFlag<"emit-pristine-llvm">, HelpText<"Emit pristine LLVM IR from the frontend by not running any LLVM passes at all." "Same as -S + -emit-llvm + -disable-llvm-passes.">; diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 559af32dc3808..9c938490035bc 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -62,6 +62,10 @@ bool isLegalShaderModel(Triple &T) { VersionTuple MinVer(6, 5); return MinVer <= Version; } break; + case Triple::EnvironmentType::RootSignature: + VersionTuple MinVer(1, 0); + VersionTuple MaxVer(1, 1); + return MinVer <= Version && Version <= MaxVer; } return false; } @@ -84,6 +88,7 @@ std::optional<std::string> tryParseProfile(StringRef Profile) { .Case("lib", Triple::EnvironmentType::Library) .Case("ms", Triple::EnvironmentType::Mesh) .Case("as", Triple::EnvironmentType::Amplification) + .Case("rootsig", Triple::EnvironmentType::RootSignature) .Default(Triple::EnvironmentType::UnknownEnvironment); if (Kind == Triple::EnvironmentType::UnknownEnvironment) return std::nullopt; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index fb8f131d1e11b..5bfdee92127b4 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -765,6 +765,8 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { case llvm::Triple::UnknownEnvironment: case llvm::Triple::Library: break; + case llvm::Triple::RootSignature: + llvm_unreachable("rootsig environment has no functions"); default: llvm_unreachable("Unhandled environment in triple"); } @@ -827,6 +829,8 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { } } break; + case llvm::Triple::RootSignature: + llvm_unreachable("rootsig environment has no function entry point"); default: llvm_unreachable("Unhandled environment in triple"); } diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 8e12c6852075d..c8fa482a9a4f4 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -305,6 +305,7 @@ class Triple { Callable, Mesh, Amplification, + RootSignature, OpenCL, OpenHOS, Mlibc, @@ -872,7 +873,7 @@ class Triple { Env == Triple::Intersection || Env == Triple::AnyHit || Env == Triple::ClosestHit || Env == Triple::Miss || Env == Triple::Callable || Env == Triple::Mesh || - Env == Triple::Amplification; + Env == Triple::Amplification || Env == Triple::RootSignature; } /// Tests whether the target is SPIR (32- or 64-bit). diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp index 82bcacee7a6dd..9eebcc9b13063 100644 --- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp +++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp @@ -127,6 +127,8 @@ static StringRef getShortShaderStage(Triple::EnvironmentType Env) { return "ms"; case Triple::Amplification: return "as"; + case Triple::RootSignature: + return "rootsig"; default: break; } diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index 71517e5e9e832..ac3626db46ea9 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -391,6 +391,8 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case Callable: return "callable"; case Mesh: return "mesh"; case Amplification: return "amplification"; + case RootSignature: + return "rootsignature"; case OpenCL: return "opencl"; case OpenHOS: return "ohos"; @@ -787,6 +789,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .StartsWith("callable", Triple::Callable) .StartsWith("mesh", Triple::Mesh) .StartsWith("amplification", Triple::Amplification) + .StartsWith("rootsignature", Triple::RootSignature) .StartsWith("opencl", Triple::OpenCL) .StartsWith("ohos", Triple::OpenHOS) .StartsWith("pauthtest", Triple::PAuthTest) >From a2035d0edc75fa5bf5972c15f3f748135cd7a8fb Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 12:40:32 -0700 Subject: [PATCH 02/17] add profile test --- llvm/unittests/TargetParser/TripleTest.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp index d2ca30583fe82..e6979cf49ce82 100644 --- a/llvm/unittests/TargetParser/TripleTest.cpp +++ b/llvm/unittests/TargetParser/TripleTest.cpp @@ -546,6 +546,22 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(VersionTuple(1, 8), T.getDXILVersion()); EXPECT_EQ(Triple::Amplification, T.getEnvironment()); + T = Triple("dxilv1.0-unknown-shadermodel1.0-rootsignature"); + EXPECT_EQ(Triple::dxil, T.getArch()); + EXPECT_EQ(Triple::DXILSubArch_v1_0, T.getSubArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::ShaderModel, T.getOS()); + EXPECT_EQ(VersionTuple(1, 0), T.getDXILVersion()); + EXPECT_EQ(Triple::RootSignature, T.getEnvironment()); + + T = Triple("dxilv1.1-unknown-shadermodel1.1-rootsignature"); + EXPECT_EQ(Triple::dxil, T.getArch()); + EXPECT_EQ(Triple::DXILSubArch_v1_1, T.getSubArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::ShaderModel, T.getOS()); + EXPECT_EQ(VersionTuple(1, 1), T.getDXILVersion()); + EXPECT_EQ(Triple::RootSignature, T.getEnvironment()); + T = Triple("dxilv1.8-unknown-shadermodel6.15-library"); EXPECT_EQ(Triple::dxil, T.getArch()); EXPECT_EQ(Triple::DXILSubArch_v1_8, T.getSubArch()); >From 410e0c8a314ce80b8286f948a10b9318306f137b Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Fri, 29 Aug 2025 10:26:38 -0700 Subject: [PATCH 03/17] introduce custom handling for root signature target --- .../clang/Parse/ParseHLSLRootSignature.h | 2 ++ clang/lib/Frontend/FrontendActions.cpp | 14 ++++++++++-- clang/lib/Parse/ParseHLSLRootSignature.cpp | 22 ++++++++++++++++++- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index c87e6637c7fce..2ae383c38a486 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -240,6 +240,8 @@ IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature); +void HandleRootSignatureTarget(Sema &S); + } // namespace hlsl } // namespace clang diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index ccda2c4ce4b6d..666923101401b 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1296,6 +1296,9 @@ class InjectRootSignatureCallback : public PPCallbacks { void HLSLFrontendAction::ExecuteAction() { // Pre-requisites to invoke + if (getCurrentFileKind().getLanguage() != Language::HLSL) + return WrapperFrontendAction::ExecuteAction(); + CompilerInstance &CI = getCompilerInstance(); if (!CI.hasASTContext() || !CI.hasPreprocessor()) return WrapperFrontendAction::ExecuteAction(); @@ -1309,6 +1312,10 @@ void HLSLFrontendAction::ExecuteAction() { /*CodeCompleteConsumer=*/nullptr); Sema &S = CI.getSema(); + auto &TargetInfo = CI.getASTContext().getTargetInfo(); + bool IsRootSignatureTarget = + TargetInfo.getTriple().getEnvironment() == llvm::Triple::RootSignature; + // Register HLSL specific callbacks auto LangOpts = CI.getLangOpts(); auto MacroCallback = std::make_unique<InjectRootSignatureCallback>( @@ -1317,8 +1324,11 @@ void HLSLFrontendAction::ExecuteAction() { Preprocessor &PP = CI.getPreprocessor(); PP.addPPCallbacks(std::move(MacroCallback)); - // Invoke as normal - WrapperFrontendAction::ExecuteAction(); + // If we are targeting a root signature, invoke custom handling + if (IsRootSignatureTarget) + return hlsl::HandleRootSignatureTarget(S); + else // otherwise, invoke as normal + return WrapperFrontendAction::ExecuteAction(); } HLSLFrontendAction::HLSLFrontendAction( diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 1af72f8b1c934..11af62f132be8 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/ParseHLSLRootSignature.h" - +#include "clang/AST/ASTConsumer.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Parse/Parser.h" #include "clang/Sema/Sema.h" using namespace llvm::hlsl::rootsig; @@ -1472,5 +1473,24 @@ IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, return DeclIdent; } +void HandleRootSignatureTarget(Sema &S) { + ASTConsumer *Consumer = &S.getASTConsumer(); + + // Minimally initalize the parser. This does a couple things: + // - initializes Sema scope handling + // - invokes HLSLExternalSemaSource + // - invokes the preprocessor to lex the macros in the file + std::unique_ptr<Parser> P(new Parser(S.getPreprocessor(), S, true)); + S.getPreprocessor().EnterMainSourceFile(); + + bool HaveLexer = S.getPreprocessor().getCurrentLexer(); + if (HaveLexer) { + P->Initialize(); + S.ActOnStartOfTranslationUnit(); + } + + Consumer->HandleTranslationUnit(S.getASTContext()); +} + } // namespace hlsl } // namespace clang >From 0ea3f1905e6e179265610d5de4a9fa310dcf7077 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Fri, 29 Aug 2025 10:45:00 -0700 Subject: [PATCH 04/17] nfc: pull out lookup of root signature --- clang/include/clang/Sema/SemaHLSL.h | 2 ++ clang/lib/Sema/SemaHLSL.cpp | 34 ++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 5cbe1b658f5cd..4bad26e7a09a7 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -157,6 +157,8 @@ class SemaHLSL : public SemaBase { RootSigOverrideIdent = DeclIdent; } + HLSLRootSignatureDecl *lookupRootSignatureOverrideDecl(DeclContext *DC) const; + // Returns true if any RootSignatureElement is invalid and a diagnostic was // produced bool diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 5bfdee92127b4..21e5b331b517c 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -729,19 +729,15 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { // If we have specified a root signature to override the entry function then // attach it now - if (RootSigOverrideIdent) { - LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(), - Sema::LookupOrdinaryName); - if (SemaRef.LookupQualifiedName(R, FD->getDeclContext())) - if (auto *SignatureDecl = - dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) { - FD->dropAttr<RootSignatureAttr>(); - // We could look up the SourceRange of the macro here as well - AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(), - SourceRange(), ParsedAttr::Form::Microsoft()); - FD->addAttr(::new (getASTContext()) RootSignatureAttr( - getASTContext(), AL, RootSigOverrideIdent, SignatureDecl)); - } + HLSLRootSignatureDecl *SignatureDecl = + lookupRootSignatureOverrideDecl(FD->getDeclContext()); + if (SignatureDecl) { + FD->dropAttr<RootSignatureAttr>(); + // We could look up the SourceRange of the macro here as well + AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(), + SourceRange(), ParsedAttr::Form::Microsoft()); + FD->addAttr(::new (getASTContext()) RootSignatureAttr( + getASTContext(), AL, RootSigOverrideIdent, SignatureDecl)); } llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment(); @@ -1111,6 +1107,18 @@ void SemaHLSL::ActOnFinishRootSignatureDecl( SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); } +HLSLRootSignatureDecl * +SemaHLSL::lookupRootSignatureOverrideDecl(DeclContext *DC) const { + if (RootSigOverrideIdent) { + LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(), + Sema::LookupOrdinaryName); + if (SemaRef.LookupQualifiedName(R, DC)) + return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl()); + } + + return nullptr; +} + namespace { struct PerVisibilityBindingChecker { >From 39e05a7dcacab90c6bce58749609b9aee0304f04 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 11:34:15 -0700 Subject: [PATCH 05/17] construct the RootSignatureDecl node in ASTContext --- .../clang/Basic/DiagnosticSemaKinds.td | 2 ++ .../clang/Parse/ParseHLSLRootSignature.h | 2 +- clang/lib/Frontend/FrontendActions.cpp | 8 ++++-- clang/lib/Parse/ParseHLSLRootSignature.cpp | 12 +++++++- .../AST/HLSL/RootSignature-Target-AST.hlsl | 28 +++++++++++++++++++ .../SemaHLSL/RootSignature-target-err.hlsl | 5 ++++ 6 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 clang/test/AST/HLSL/RootSignature-Target-AST.hlsl create mode 100644 clang/test/SemaHLSL/RootSignature-target-err.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 711efbe727892..e78064fd676d7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13147,6 +13147,8 @@ def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used on def err_hlsl_incorrect_num_initializers: Error< "too %select{few|many}0 initializers in list for type %1 " "(expected %2 but found %3)">; +def err_hlsl_rootsignature_entry: Error< + "rootsignature specified as target environment but entry, %0, was not defined">; def err_hlsl_operator_unsupported : Error< "the '%select{&|*|->}0' operator is unsupported in HLSL">; diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index 2ae383c38a486..b06846fd83c09 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -240,7 +240,7 @@ IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature); -void HandleRootSignatureTarget(Sema &S); +void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig); } // namespace hlsl } // namespace clang diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 666923101401b..9e00494bcfbcf 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1315,18 +1315,22 @@ void HLSLFrontendAction::ExecuteAction() { auto &TargetInfo = CI.getASTContext().getTargetInfo(); bool IsRootSignatureTarget = TargetInfo.getTriple().getEnvironment() == llvm::Triple::RootSignature; + StringRef HLSLEntry = TargetInfo.getTargetOpts().HLSLEntry; // Register HLSL specific callbacks auto LangOpts = CI.getLangOpts(); + StringRef RootSigName = + IsRootSignatureTarget ? HLSLEntry : LangOpts.HLSLRootSigOverride; + auto MacroCallback = std::make_unique<InjectRootSignatureCallback>( - S, LangOpts.HLSLRootSigOverride, LangOpts.HLSLRootSigVer); + S, RootSigName, LangOpts.HLSLRootSigVer); Preprocessor &PP = CI.getPreprocessor(); PP.addPPCallbacks(std::move(MacroCallback)); // If we are targeting a root signature, invoke custom handling if (IsRootSignatureTarget) - return hlsl::HandleRootSignatureTarget(S); + return hlsl::HandleRootSignatureTarget(S, HLSLEntry); else // otherwise, invoke as normal return WrapperFrontendAction::ExecuteAction(); } diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 11af62f132be8..4e5b8b83200e0 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -1473,7 +1473,7 @@ IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, return DeclIdent; } -void HandleRootSignatureTarget(Sema &S) { +void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) { ASTConsumer *Consumer = &S.getASTConsumer(); // Minimally initalize the parser. This does a couple things: @@ -1487,6 +1487,16 @@ void HandleRootSignatureTarget(Sema &S) { if (HaveLexer) { P->Initialize(); S.ActOnStartOfTranslationUnit(); + + HLSLRootSignatureDecl *SignatureDecl = + S.HLSL().lookupRootSignatureOverrideDecl( + S.getASTContext().getTranslationUnitDecl()); + + if (SignatureDecl) + Consumer->HandleTopLevelDecl(DeclGroupRef(SignatureDecl)); + else + S.getDiagnostics().Report(diag::err_hlsl_rootsignature_entry) + << EntryRootSig; } Consumer->HandleTranslationUnit(S.getASTContext()); diff --git a/clang/test/AST/HLSL/RootSignature-Target-AST.hlsl b/clang/test/AST/HLSL/RootSignature-Target-AST.hlsl new file mode 100644 index 0000000000000..91441e32e047d --- /dev/null +++ b/clang/test/AST/HLSL/RootSignature-Target-AST.hlsl @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -ast-dump \ +// RUN: -hlsl-entry EntryRootSig -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-V1_1 + +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -ast-dump \ +// RUN: -fdx-rootsignature-version=rootsig_1_0 \ +// RUN: -hlsl-entry EntryRootSig -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-V1_0 + +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -ast-dump \ +// RUN: -D CmdRS='"UAV(u0)"'\ +// RUN: -hlsl-entry CmdRS -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CMD + +// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[ENTRY_RS_DECL:__hlsl_rootsig_decl_\d*]] +// CHECK-V1_0-SAME: version: 1.0, +// CHECK-V1_1-SAME: version: 1.1, +// CHECK-SAME: RootElements{ +// CHECK-SAME: RootCBV(b0, +// CHECK-SAME: space = 0, visibility = All, +// CHECK-V1_0-SAME: flags = DataVolatile +// CHECK-V1_1-SAME: flags = DataStaticWhileSetAtExecute +// CHECK-SAME: ) +// CHECK-SAME: } +#define EntryRootSig "CBV(b0)" + +// CMD: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[CMD_RS_DECL:__hlsl_rootsig_decl_\d*]] +// CMD-SAME: version: 1.1, +// CMD-SAME: RootElements{ +// CMD-SAME: RootUAV(u0, space = 0, visibility = All, flags = DataVolatile) +// CMD-SAME: } diff --git a/clang/test/SemaHLSL/RootSignature-target-err.hlsl b/clang/test/SemaHLSL/RootSignature-target-err.hlsl new file mode 100644 index 0000000000000..49aca9ed6b377 --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-target-err.hlsl @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -hlsl-entry NotFoundRS -fsyntax-only %s -verify + +// expected-error@* {{rootsignature specified as target environment but entry, NotFoundRS, was not defined}} + +#define EntryRootSig "CBV(b0)" >From 069145e531e7f3f0fe74c9ef8a0211c515563df9 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 11:55:24 -0700 Subject: [PATCH 06/17] add support for generating the metadata --- clang/lib/CodeGen/CGHLSLRuntime.cpp | 28 ++++++++++++++----- clang/lib/CodeGen/CGHLSLRuntime.h | 2 ++ clang/lib/CodeGen/CodeGenModule.cpp | 2 +- .../CodeGenHLSL/RootSignature-Target.hlsl | 9 ++++++ 4 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 clang/test/CodeGenHLSL/RootSignature-Target.hlsl diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index d27f3781c69a3..c9ab277762fa0 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -69,9 +69,9 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) { DXILValMD->addOperand(Val); } -void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer, - ArrayRef<llvm::hlsl::rootsig::RootElement> Elements, - llvm::Function *Fn, llvm::Module &M) { +void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer, + ArrayRef<llvm::hlsl::rootsig::RootElement> Elements, + llvm::Function *Fn, llvm::Module &M) { auto &Ctx = M.getContext(); llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements); @@ -79,8 +79,8 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer, ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get( llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer))); - MDNode *MDVals = - MDNode::get(Ctx, {ValueAsMetadata::get(Fn), RootSignature, Version}); + ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr; + MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version}); StringRef RootSignatureValKey = "dx.rootsignatures"; auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey); @@ -448,6 +448,20 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) { } } +void CGHLSLRuntime::addRootSignature( + const HLSLRootSignatureDecl *SignatureDecl) { + llvm::Module &M = CGM.getModule(); + Triple T(M.getTargetTriple()); + + // If we are not targeting a root signature enviornment then this decl will + // be generated when the function decl it is attached is handled + if (T.getEnvironment() != Triple::EnvironmentType::RootSignature) + return; + + addRootSignatureMD(SignatureDecl->getVersion(), + SignatureDecl->getRootElements(), nullptr, M); +} + llvm::TargetExtType * CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) { const auto Entry = LayoutTypes.find(StructType); @@ -651,8 +665,8 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, for (const Attr *Attr : FD->getAttrs()) { if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) { auto *RSDecl = RSAttr->getSignatureDecl(); - addRootSignature(RSDecl->getVersion(), RSDecl->getRootElements(), EntryFn, - M); + addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(), + EntryFn, M); } } } diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 0582be3d99ec4..0948fefe7685e 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -62,6 +62,7 @@ class VarDecl; class ParmVarDecl; class InitListExpr; class HLSLBufferDecl; +class HLSLRootSignatureDecl; class HLSLVkBindingAttr; class HLSLResourceBindingAttr; class Type; @@ -151,6 +152,7 @@ class CGHLSLRuntime { void generateGlobalCtorDtorCalls(); void addBuffer(const HLSLBufferDecl *D); + void addRootSignature(const HLSLRootSignatureDecl *D); void finishCodeGen(); void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c0cfc24f02877..02fbb952f6443 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7537,7 +7537,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; case Decl::HLSLRootSignature: - // Will be handled by attached function + getHLSLRuntime().addRootSignature(cast<HLSLRootSignatureDecl>(D)); break; case Decl::HLSLBuffer: getHLSLRuntime().addBuffer(cast<HLSLBufferDecl>(D)); diff --git a/clang/test/CodeGenHLSL/RootSignature-Target.hlsl b/clang/test/CodeGenHLSL/RootSignature-Target.hlsl new file mode 100644 index 0000000000000..50e6bae6786f0 --- /dev/null +++ b/clang/test/CodeGenHLSL/RootSignature-Target.hlsl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-rootsignature \ +// RUN: -hlsl-entry EntryRS -emit-llvm -o - %s | FileCheck %s + +// CHECK: !dx.rootsignatures = !{![[#ENTRY:]]} +// CHECK: ![[#ENTRY]] = !{null, ![[#ENTRY_RS:]], i32 2} +// CHECK: ![[#ENTRY_RS]] = !{![[#ROOT_CBV:]]} +// CHECK: ![[#ROOT_CBV]] = !{!"RootCBV", i32 0, i32 0, i32 0, i32 4} + +#define EntryRS "CBV(b0)" >From 29462da66bec98b5198addaaf06f3a57a5a6c949 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 11:56:42 -0700 Subject: [PATCH 07/17] nfc: pull out handling of rs node --- llvm/lib/Target/DirectX/DXILRootSignature.cpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp index 2436d3869464f..5b70e29a12073 100644 --- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp +++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp @@ -72,11 +72,11 @@ analyzeModule(Module &M) { if (RootSignatureNode == nullptr) return RSDMap; - for (const auto &RSDefNode : RootSignatureNode->operands()) { + auto HandleNode = [&Ctx, &RSDMap](MDNode *RSDefNode) { if (RSDefNode->getNumOperands() != 3) { reportError(Ctx, "Invalid Root Signature metadata - expected function, " "signature, and version."); - continue; + return; } // Function was pruned during compilation. @@ -84,38 +84,38 @@ analyzeModule(Module &M) { if (FunctionPointerMdNode == nullptr) { reportError( Ctx, "Function associated with Root Signature definition is null."); - continue; + return; } ValueAsMetadata *VAM = llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get()); if (VAM == nullptr) { reportError(Ctx, "First element of root signature is not a Value"); - continue; + return; } Function *F = dyn_cast<Function>(VAM->getValue()); if (F == nullptr) { reportError(Ctx, "First element of root signature is not a Function"); - continue; + return; } Metadata *RootElementListOperand = RSDefNode->getOperand(1).get(); if (RootElementListOperand == nullptr) { reportError(Ctx, "Root Element mdnode is null."); - continue; + return; } MDNode *RootElementListNode = dyn_cast<MDNode>(RootElementListOperand); if (RootElementListNode == nullptr) { reportError(Ctx, "Root Element is not a metadata node."); - continue; + return; } std::optional<uint32_t> V = extractMdIntValue(RSDefNode, 2); if (!V.has_value()) { reportError(Ctx, "Invalid RSDefNode value, expected constant int"); - continue; + return; } llvm::hlsl::rootsig::MetadataParser MDParser(RootElementListNode); @@ -126,7 +126,7 @@ analyzeModule(Module &M) { handleAllErrors(RSDOrErr.takeError(), [&](ErrorInfoBase &EIB) { Ctx->emitError(EIB.message()); }); - continue; + return; } auto &RSD = *RSDOrErr; @@ -140,8 +140,12 @@ analyzeModule(Module &M) { RSD.StaticSamplersOffset = 0u; RSDMap.insert(std::make_pair(F, RSD)); + }; } + for (MDNode *RSDefNode : RootSignatureNode->operands()) + HandleNode(RSDefNode); + return RSDMap; } >From ef1bce920817d56e0a4ec4708c0c2b69e9c0c729 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Fri, 29 Aug 2025 15:38:09 -0700 Subject: [PATCH 08/17] add support constructing dxcontainer for rootsignature without entry function --- llvm/include/llvm/BinaryFormat/DXContainer.h | 2 +- .../lib/Target/DirectX/DXContainerGlobals.cpp | 16 +++++-- llvm/lib/Target/DirectX/DXILRootSignature.cpp | 46 +++++++++++-------- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h index f74c9775cb3f3..0547d96a8dec7 100644 --- a/llvm/include/llvm/BinaryFormat/DXContainer.h +++ b/llvm/include/llvm/BinaryFormat/DXContainer.h @@ -45,7 +45,7 @@ namespace dxbc { LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); inline Triple::EnvironmentType getShaderStage(uint32_t Kind) { - assert(Kind <= Triple::Amplification - Triple::Pixel && + assert(Kind <= Triple::RootSignature - Triple::Pixel && "Shader kind out of expected range."); return static_cast<Triple::EnvironmentType>(Triple::Pixel + Kind); } diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp index a1ef2578f00aa..37c58e041f4df 100644 --- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp +++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp @@ -158,10 +158,14 @@ void DXContainerGlobals::addRootSignature(Module &M, if (MMI.ShaderProfile == llvm::Triple::Library) return; - assert(MMI.EntryPropertyVec.size() == 1); - auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo(); - const Function *EntryFunction = MMI.EntryPropertyVec[0].Entry; + const Function *EntryFunction = nullptr; + + if (MMI.ShaderProfile != llvm::Triple::RootSignature) { + assert(MMI.EntryPropertyVec.size() == 1); + EntryFunction = MMI.EntryPropertyVec[0].Entry; + } + const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction); if (!RS) @@ -258,7 +262,8 @@ void DXContainerGlobals::addPipelineStateValidationInfo( dxil::ModuleMetadataInfo &MMI = getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata(); assert(MMI.EntryPropertyVec.size() == 1 || - MMI.ShaderProfile == Triple::Library); + MMI.ShaderProfile == Triple::Library || + MMI.ShaderProfile == Triple::RootSignature); PSV.BaseData.ShaderStage = static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel); @@ -279,7 +284,8 @@ void DXContainerGlobals::addPipelineStateValidationInfo( break; } - if (MMI.ShaderProfile != Triple::Library) + if (MMI.ShaderProfile != Triple::Library && + MMI.ShaderProfile != Triple::RootSignature) PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName(); PSV.finalize(MMI.ShaderProfile); diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp index 5b70e29a12073..8db9436eabc57 100644 --- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp +++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp @@ -72,32 +72,35 @@ analyzeModule(Module &M) { if (RootSignatureNode == nullptr) return RSDMap; - auto HandleNode = [&Ctx, &RSDMap](MDNode *RSDefNode) { + auto HandleNode = [&Ctx, &RSDMap](MDNode *RSDefNode, bool NullFunc = false) { if (RSDefNode->getNumOperands() != 3) { reportError(Ctx, "Invalid Root Signature metadata - expected function, " "signature, and version."); return; } - // Function was pruned during compilation. - const MDOperand &FunctionPointerMdNode = RSDefNode->getOperand(0); - if (FunctionPointerMdNode == nullptr) { - reportError( - Ctx, "Function associated with Root Signature definition is null."); - return; - } + Function *F = nullptr; + if (!NullFunc) { + // Function was pruned during compilation. + const MDOperand &FunctionPointerMdNode = RSDefNode->getOperand(0); + if (FunctionPointerMdNode == nullptr) { + reportError( + Ctx, "Function associated with Root Signature definition is null."); + return; + } - ValueAsMetadata *VAM = - llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get()); - if (VAM == nullptr) { - reportError(Ctx, "First element of root signature is not a Value"); - return; - } + ValueAsMetadata *VAM = + llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get()); + if (VAM == nullptr) { + reportError(Ctx, "First element of root signature is not a Value"); + return; + } - Function *F = dyn_cast<Function>(VAM->getValue()); - if (F == nullptr) { - reportError(Ctx, "First element of root signature is not a Function"); - return; + F = dyn_cast<Function>(VAM->getValue()); + if (F == nullptr) { + reportError(Ctx, "First element of root signature is not a Function"); + return; + } } Metadata *RootElementListOperand = RSDefNode->getOperand(1).get(); @@ -141,6 +144,13 @@ analyzeModule(Module &M) { RSDMap.insert(std::make_pair(F, RSD)); }; + + if (M.getTargetTriple().getEnvironment() == + Triple::EnvironmentType::RootSignature) { + assert(RootSignatureNode->getNumOperands() == 1); + MDNode *RSDefNode = RootSignatureNode->getOperand(0); + HandleNode(RSDefNode, true); + return RSDMap; } for (MDNode *RSDefNode : RootSignatureNode->operands()) >From c6f7623ca2a959fc50feffaf4ad131942ec5973f Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 12:39:50 -0700 Subject: [PATCH 09/17] nfc: extract intermediate parse profile step --- clang/lib/Driver/ToolChains/HLSL.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 9c938490035bc..875996e1523b2 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -70,7 +70,7 @@ bool isLegalShaderModel(Triple &T) { return false; } -std::optional<std::string> tryParseProfile(StringRef Profile) { +std::optional<llvm::Triple> tryParseTriple(StringRef Profile) { // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] SmallVector<StringRef, 3> Parts; Profile.split(Parts, "_"); @@ -152,8 +152,14 @@ std::optional<std::string> tryParseProfile(StringRef Profile) { T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + VersionTuple(Major, Minor).getAsString()); T.setEnvironment(Kind); - if (isLegalShaderModel(T)) - return T.getTriple(); + + return T; +} + +std::optional<std::string> tryParseProfile(StringRef Profile) { + std::optional<llvm::Triple> MaybeT = tryParseTriple(Profile); + if (MaybeT && isLegalShaderModel(*MaybeT)) + return MaybeT->getTriple(); else return std::nullopt; } >From 857f48f9ec4fb2891ec041affe39076b09657e9c Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 12:40:20 -0700 Subject: [PATCH 10/17] add invocation to just emit root signature of dxcontainer --- clang/lib/Driver/ToolChains/HLSL.cpp | 22 ++++++++++++++++++- .../test/Driver/dxc_rootsignature_target.hlsl | 8 +++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 clang/test/Driver/dxc_rootsignature_target.hlsl diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 875996e1523b2..b36297c169376 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -269,6 +269,19 @@ bool checkExtensionArgsAreValid(ArrayRef<std::string> SpvExtensionArgs, } return AllValid; } + +bool isRootSignatureTarget(StringRef Profile) { + if (std::optional<llvm::Triple> T = tryParseTriple(Profile)) + return T->getEnvironment() == Triple::EnvironmentType::RootSignature; + return false; +} + +bool isRootSignatureTarget(DerivedArgList &Args) { + if (const Arg *A = Args.getLastArg(options::OPT_target_profile)) + return isRootSignatureTarget(A->getValue()); + return false; +} + } // namespace void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA, @@ -328,6 +341,12 @@ void tools::hlsl::LLVMObjcopy::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Frs); } + if (const Arg *A = Args.getLastArg(options::OPT_target_profile)) + if (isRootSignatureTarget(A->getValue())) { + const char *Fos = Args.MakeArgString("--only-section=RTS0"); + CmdArgs.push_back(Fos); + } + assert(CmdArgs.size() > 2 && "Unnecessary invocation of objcopy."); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), @@ -504,7 +523,8 @@ bool HLSLToolChain::requiresBinaryTranslation(DerivedArgList &Args) const { bool HLSLToolChain::requiresObjcopy(DerivedArgList &Args) const { return Args.hasArg(options::OPT_dxc_Fo) && - Args.hasArg(options::OPT_dxc_strip_rootsignature); + (Args.hasArg(options::OPT_dxc_strip_rootsignature) || + isRootSignatureTarget(Args)); } bool HLSLToolChain::isLastJob(DerivedArgList &Args, diff --git a/clang/test/Driver/dxc_rootsignature_target.hlsl b/clang/test/Driver/dxc_rootsignature_target.hlsl new file mode 100644 index 0000000000000..a732c50507cdb --- /dev/null +++ b/clang/test/Driver/dxc_rootsignature_target.hlsl @@ -0,0 +1,8 @@ +// RUN: %clang_dxc -E EntryRS -T rootsig_1_1 /Fo %t.dxo -### %s 2>&1 | FileCheck %s --check-prefix=CMDS + +// CMDS: "{{.*}}clang{{.*}}" "-cc1" +// CMDS-SAME: "-triple" "dxilv1.1-unknown-shadermodel1.1-rootsignature" +// CMDS-SAME: "-hlsl-entry" "EntryRS" +// CMDS: "{{.*}}llvm-objcopy{{(.exe)?}}" "{{.*}}.dxo" "--only-section=RTS0" + +#define EntryRS "CBV(b0)" >From c4e7a60c21ebb94ad568f53816da680a43bdd3f2 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Mon, 1 Sep 2025 12:57:54 -0700 Subject: [PATCH 11/17] add clang_dxc test to demonstrate lexing bug --- clang/lib/Parse/ParseHLSLRootSignature.cpp | 4 +++ .../test/Driver/dxc_rootsignature_target.hlsl | 34 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 4e5b8b83200e0..91976489ee660 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -1488,6 +1488,10 @@ void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) { P->Initialize(); S.ActOnStartOfTranslationUnit(); + // Skim through the file to parse to find the define + while (P->getCurToken().getKind() != tok::eof) + P->ConsumeAnyToken(); + HLSLRootSignatureDecl *SignatureDecl = S.HLSL().lookupRootSignatureOverrideDecl( S.getASTContext().getTranslationUnitDecl()); diff --git a/clang/test/Driver/dxc_rootsignature_target.hlsl b/clang/test/Driver/dxc_rootsignature_target.hlsl index a732c50507cdb..011fa4be9050d 100644 --- a/clang/test/Driver/dxc_rootsignature_target.hlsl +++ b/clang/test/Driver/dxc_rootsignature_target.hlsl @@ -1,8 +1,40 @@ // RUN: %clang_dxc -E EntryRS -T rootsig_1_1 /Fo %t.dxo -### %s 2>&1 | FileCheck %s --check-prefix=CMDS +// RUN: %clang_dxc -E EntryRS -T rootsig_1_1 /Fo %t.dxo %s +// RUN: obj2yaml %t.dxo | FileCheck %s --check-prefix=OBJ + // CMDS: "{{.*}}clang{{.*}}" "-cc1" // CMDS-SAME: "-triple" "dxilv1.1-unknown-shadermodel1.1-rootsignature" // CMDS-SAME: "-hlsl-entry" "EntryRS" // CMDS: "{{.*}}llvm-objcopy{{(.exe)?}}" "{{.*}}.dxo" "--only-section=RTS0" -#define EntryRS "CBV(b0)" +#define EntryRS "UAV(u0)" + +// OBJ: --- !dxcontainer +// FileSize = 32 (header) + 48 (RTS0 content) + 4 (1 part offset) + 8 (1 part header) +// OBJ: FileSize: 92 +// OBJ-NEXT: PartCount: 1 +// OBJ-NEXT: PartOffsets: [ 36 ] +// OBJ-NEXT: Parts: +// OBJ-NOT: DXIL +// OBJ-NOT: SFI0 +// OBJ-NOT: HASH +// OBJ-NOT: ISG0 +// OBJ-NOT: OSG0 + +// OBJ: - Name: RTS0 +// OBJ-NEXT: Size: 48 +// OBJ-NEXT: RootSignature: +// OBJ-NEXT: Version: 2 +// OBJ-NEXT: NumRootParameters: 1 +// OBJ-NEXT: RootParametersOffset: 24 + +// OBJ: Parameters: +// UAV(u0) +// OBJ: - ParameterType: 4 +// OBJ-NEXT: ShaderVisibility: 0 +// OBJ-NEXT: Descriptor: +// OBJ-NEXT: RegisterSpace: 0 +// OBJ-NEXT: ShaderRegister: 0 + +// OBJ-NOT: PSV0 >From 980ef057bc13f112f35ed8fade6b11d5fa882a65 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Tue, 2 Sep 2025 13:32:05 -0700 Subject: [PATCH 12/17] Revert "add clang_dxc test to demonstrate lexing bug" This reverts commit 50d72e692c0d45134422956fff10e779ce822b7f. --- clang/lib/Parse/ParseHLSLRootSignature.cpp | 4 --- .../test/Driver/dxc_rootsignature_target.hlsl | 32 ------------------- 2 files changed, 36 deletions(-) diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 91976489ee660..4e5b8b83200e0 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -1488,10 +1488,6 @@ void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) { P->Initialize(); S.ActOnStartOfTranslationUnit(); - // Skim through the file to parse to find the define - while (P->getCurToken().getKind() != tok::eof) - P->ConsumeAnyToken(); - HLSLRootSignatureDecl *SignatureDecl = S.HLSL().lookupRootSignatureOverrideDecl( S.getASTContext().getTranslationUnitDecl()); diff --git a/clang/test/Driver/dxc_rootsignature_target.hlsl b/clang/test/Driver/dxc_rootsignature_target.hlsl index 011fa4be9050d..08cd1ab00089b 100644 --- a/clang/test/Driver/dxc_rootsignature_target.hlsl +++ b/clang/test/Driver/dxc_rootsignature_target.hlsl @@ -1,40 +1,8 @@ // RUN: %clang_dxc -E EntryRS -T rootsig_1_1 /Fo %t.dxo -### %s 2>&1 | FileCheck %s --check-prefix=CMDS -// RUN: %clang_dxc -E EntryRS -T rootsig_1_1 /Fo %t.dxo %s -// RUN: obj2yaml %t.dxo | FileCheck %s --check-prefix=OBJ - // CMDS: "{{.*}}clang{{.*}}" "-cc1" // CMDS-SAME: "-triple" "dxilv1.1-unknown-shadermodel1.1-rootsignature" // CMDS-SAME: "-hlsl-entry" "EntryRS" // CMDS: "{{.*}}llvm-objcopy{{(.exe)?}}" "{{.*}}.dxo" "--only-section=RTS0" #define EntryRS "UAV(u0)" - -// OBJ: --- !dxcontainer -// FileSize = 32 (header) + 48 (RTS0 content) + 4 (1 part offset) + 8 (1 part header) -// OBJ: FileSize: 92 -// OBJ-NEXT: PartCount: 1 -// OBJ-NEXT: PartOffsets: [ 36 ] -// OBJ-NEXT: Parts: -// OBJ-NOT: DXIL -// OBJ-NOT: SFI0 -// OBJ-NOT: HASH -// OBJ-NOT: ISG0 -// OBJ-NOT: OSG0 - -// OBJ: - Name: RTS0 -// OBJ-NEXT: Size: 48 -// OBJ-NEXT: RootSignature: -// OBJ-NEXT: Version: 2 -// OBJ-NEXT: NumRootParameters: 1 -// OBJ-NEXT: RootParametersOffset: 24 - -// OBJ: Parameters: -// UAV(u0) -// OBJ: - ParameterType: 4 -// OBJ-NEXT: ShaderVisibility: 0 -// OBJ-NEXT: Descriptor: -// OBJ-NEXT: RegisterSpace: 0 -// OBJ-NEXT: ShaderRegister: 0 - -// OBJ-NOT: PSV0 >From 5189020c46f92b7ce93db053582a1c8e11637848 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Tue, 2 Sep 2025 13:34:53 -0700 Subject: [PATCH 13/17] add skimming of main file to ignore invalid code - P->Initialize() will only parse until the first non-preprocessor token is found. If a user specifies any code before their entry root signature macro definition, we would not find the definition and incorrectly report that it is not defined This change ensures that we will parse through the entire source file to resolve our macro and match DXC's behaviour --- clang/lib/Parse/ParseHLSLRootSignature.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 4e5b8b83200e0..91976489ee660 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -1488,6 +1488,10 @@ void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) { P->Initialize(); S.ActOnStartOfTranslationUnit(); + // Skim through the file to parse to find the define + while (P->getCurToken().getKind() != tok::eof) + P->ConsumeAnyToken(); + HLSLRootSignatureDecl *SignatureDecl = S.HLSL().lookupRootSignatureOverrideDecl( S.getASTContext().getTranslationUnitDecl()); >From 20be7ebae065431045f5d2bf52f6c94469800610 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Tue, 2 Sep 2025 13:47:52 -0700 Subject: [PATCH 14/17] add missing test case for dxcontainer logic --- .../ContainerData/RootSignature-Target.ll | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll new file mode 100644 index 0000000000000..76212a0f66f9d --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll @@ -0,0 +1,23 @@ +; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s +; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC + +target triple = "dxil-unknown-shadermodel1.1-rootsignature" + +; CHECK: @dx.rts0 = private constant [24 x i8] c"{{.*}}", section "RTS0", align 4 + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ null, !3, i32 2 } ; function, root signature, version +!3 = !{ !4 } ; list of root signature elements +!4 = !{ !"RootFlags", i32 1 } ; 1 = allow_input_assembler_input_layout + +; DXC: - Name: RTS0 +; DXC-NEXT: Size: 24 +; DXC-NEXT: RootSignature: +; DXC-NEXT: Version: 2 +; DXC-NEXT: NumRootParameters: 0 +; DXC-NEXT: RootParametersOffset: 24 +; DXC-NEXT: NumStaticSamplers: 0 +; DXC-NEXT: StaticSamplersOffset: 24 +; DXC-NEXT: Parameters: [] +; DXC-NEXT: AllowInputAssemblerInputLayout: true + >From 9004e4f9ca9cb4fcb8ec60e89d8ce4b5c4309052 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Thu, 4 Sep 2025 11:18:03 -0700 Subject: [PATCH 15/17] review: use a loop for clarity --- .../lib/Target/DirectX/DXContainerGlobals.cpp | 1 - llvm/lib/Target/DirectX/DXILRootSignature.cpp | 41 +++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp index 37c58e041f4df..ca81d30473c03 100644 --- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp +++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp @@ -167,7 +167,6 @@ void DXContainerGlobals::addRootSignature(Module &M, } const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction); - if (!RS) return; diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp index 8db9436eabc57..9cfc47d187c5f 100644 --- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp +++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp @@ -72,34 +72,42 @@ analyzeModule(Module &M) { if (RootSignatureNode == nullptr) return RSDMap; - auto HandleNode = [&Ctx, &RSDMap](MDNode *RSDefNode, bool NullFunc = false) { + bool AllowNullFunctions = false; + if (M.getTargetTriple().getEnvironment() == + Triple::EnvironmentType::RootSignature) { + assert(RootSignatureNode->getNumOperands() == 1); + AllowNullFunctions = true; + } + + for (const auto &RSDefNode : RootSignatureNode->operands()) { if (RSDefNode->getNumOperands() != 3) { reportError(Ctx, "Invalid Root Signature metadata - expected function, " "signature, and version."); - return; + continue; } + // Function was pruned during compilation. Function *F = nullptr; - if (!NullFunc) { - // Function was pruned during compilation. + + if (!AllowNullFunctions) { const MDOperand &FunctionPointerMdNode = RSDefNode->getOperand(0); if (FunctionPointerMdNode == nullptr) { reportError( Ctx, "Function associated with Root Signature definition is null."); - return; + continue; } ValueAsMetadata *VAM = llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get()); if (VAM == nullptr) { reportError(Ctx, "First element of root signature is not a Value"); - return; + continue; } F = dyn_cast<Function>(VAM->getValue()); if (F == nullptr) { reportError(Ctx, "First element of root signature is not a Function"); - return; + continue; } } @@ -107,18 +115,18 @@ analyzeModule(Module &M) { if (RootElementListOperand == nullptr) { reportError(Ctx, "Root Element mdnode is null."); - return; + continue; } MDNode *RootElementListNode = dyn_cast<MDNode>(RootElementListOperand); if (RootElementListNode == nullptr) { reportError(Ctx, "Root Element is not a metadata node."); - return; + continue; } std::optional<uint32_t> V = extractMdIntValue(RSDefNode, 2); if (!V.has_value()) { reportError(Ctx, "Invalid RSDefNode value, expected constant int"); - return; + continue; } llvm::hlsl::rootsig::MetadataParser MDParser(RootElementListNode); @@ -129,7 +137,7 @@ analyzeModule(Module &M) { handleAllErrors(RSDOrErr.takeError(), [&](ErrorInfoBase &EIB) { Ctx->emitError(EIB.message()); }); - return; + continue; } auto &RSD = *RSDOrErr; @@ -143,19 +151,8 @@ analyzeModule(Module &M) { RSD.StaticSamplersOffset = 0u; RSDMap.insert(std::make_pair(F, RSD)); - }; - - if (M.getTargetTriple().getEnvironment() == - Triple::EnvironmentType::RootSignature) { - assert(RootSignatureNode->getNumOperands() == 1); - MDNode *RSDefNode = RootSignatureNode->getOperand(0); - HandleNode(RSDefNode, true); - return RSDMap; } - for (MDNode *RSDefNode : RootSignatureNode->operands()) - HandleNode(RSDefNode); - return RSDMap; } >From ccb90785c7bec11025a1876d0267c4f53bcd6e02 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Thu, 4 Sep 2025 12:10:00 -0700 Subject: [PATCH 16/17] review: remove lingering redundant check --- clang/lib/Frontend/FrontendActions.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 9e00494bcfbcf..b0d71b9636a0d 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1296,9 +1296,6 @@ class InjectRootSignatureCallback : public PPCallbacks { void HLSLFrontendAction::ExecuteAction() { // Pre-requisites to invoke - if (getCurrentFileKind().getLanguage() != Language::HLSL) - return WrapperFrontendAction::ExecuteAction(); - CompilerInstance &CI = getCompilerInstance(); if (!CI.hasASTContext() || !CI.hasPreprocessor()) return WrapperFrontendAction::ExecuteAction(); >From 19a57025e8764d65912e37efc74748cc9f714fcb Mon Sep 17 00:00:00 2001 From: Finn Plummer <canadienf...@gmail.com> Date: Mon, 8 Sep 2025 15:56:56 +0000 Subject: [PATCH 17/17] review: update comment --- clang/lib/CodeGen/CGHLSLRuntime.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index c9ab277762fa0..7fba3b4748ae8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -453,8 +453,7 @@ void CGHLSLRuntime::addRootSignature( llvm::Module &M = CGM.getModule(); Triple T(M.getTargetTriple()); - // If we are not targeting a root signature enviornment then this decl will - // be generated when the function decl it is attached is handled + // Generated later with the function decl if not targeting root signature if (T.getEnvironment() != Triple::EnvironmentType::RootSignature) return; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits