https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/154639
>From d91de5f59ab2682b1067c7881a4af995422f9dfc Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Wed, 20 Aug 2025 12:06:03 -0700 Subject: [PATCH 1/9] nfc: move invocation of parsing to common location --- .../clang/Parse/ParseHLSLRootSignature.h | 4 +++ clang/lib/Parse/ParseDeclCXX.cpp | 31 ++++++------------- clang/lib/Parse/ParseHLSLRootSignature.cpp | 24 ++++++++++++++ 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index a49bdfd51fbee..c87e6637c7fce 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -236,6 +236,10 @@ class RootSignatureParser { RootSignatureToken CurToken; }; +IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, + llvm::dxbc::RootSignatureVersion Version, + StringLiteral *Signature); + } // namespace hlsl } // namespace clang diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 3214e6f5fad2d..048eac4f8259b 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -4923,33 +4923,20 @@ void Parser::ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs) { return std::nullopt; }; - auto StrLiteral = ProcessStringLiteral(); - if (!StrLiteral.has_value()) { + auto Signature = ProcessStringLiteral(); + if (!Signature.has_value()) { Diag(Tok, diag::err_expected_string_literal) - << /*in attributes...*/ 4 << RootSignatureIdent->getName(); - SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); - T.consumeClose(); + << /*in attributes...*/ 4 << "RootSignature"; return; } // Construct our identifier - StringLiteral *Signature = StrLiteral.value(); - auto [DeclIdent, Found] = - Actions.HLSL().ActOnStartRootSignatureDecl(Signature->getString()); - // If we haven't found an already defined DeclIdent then parse the root - // signature string and construct the in-memory elements - if (!Found) { - // Invoke the root signature parser to construct the in-memory constructs - hlsl::RootSignatureParser Parser(getLangOpts().HLSLRootSigVer, Signature, - PP); - if (Parser.parse()) { - T.consumeClose(); - return; - } - - // Construct the declaration. - Actions.HLSL().ActOnFinishRootSignatureDecl(RootSignatureLoc, DeclIdent, - Parser.getElements()); + IdentifierInfo *DeclIdent = hlsl::ParseHLSLRootSignature( + Actions, getLangOpts().HLSLRootSigVer, *Signature); + if (!DeclIdent) { + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + T.consumeClose(); + return; } // Create the arg for the ParsedAttr diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 5490c61f52356..1af72f8b1c934 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -9,6 +9,7 @@ #include "clang/Parse/ParseHLSLRootSignature.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Sema/Sema.h" using namespace llvm::hlsl::rootsig; @@ -1448,5 +1449,28 @@ SourceLocation RootSignatureParser::getTokenLocation(RootSignatureToken Tok) { PP.getLangOpts(), PP.getTargetInfo()); } +IdentifierInfo *ParseHLSLRootSignature(Sema &Actions, + llvm::dxbc::RootSignatureVersion Version, + StringLiteral *Signature) { + // Construct our identifier + auto [DeclIdent, Found] = + Actions.HLSL().ActOnStartRootSignatureDecl(Signature->getString()); + // If we haven't found an already defined DeclIdent then parse the root + // signature string and construct the in-memory elements + if (!Found) { + // Invoke the root signature parser to construct the in-memory constructs + hlsl::RootSignatureParser Parser(Version, Signature, + Actions.getPreprocessor()); + if (Parser.parse()) + return nullptr; + + // Construct the declaration. + Actions.HLSL().ActOnFinishRootSignatureDecl( + Signature->getBeginLoc(), DeclIdent, Parser.getElements()); + } + + return DeclIdent; +} + } // namespace hlsl } // namespace clang >From 373add478ec656de999e3c9c1b66a2f4e6bf05cf Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Wed, 20 Aug 2025 12:06:42 -0700 Subject: [PATCH 2/9] define the `fdx-rootsignature-define` option --- clang/include/clang/Basic/LangOptions.h | 4 ++++ clang/include/clang/Driver/Options.td | 7 +++++++ clang/lib/Frontend/CompilerInvocation.cpp | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 569584bcc2297..a8943df5b39aa 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -552,6 +552,10 @@ class LangOptions : public LangOptionsBase { llvm::dxbc::RootSignatureVersion HLSLRootSigVer = llvm::dxbc::RootSignatureVersion::V1_1; + /// The HLSL root signature that will be used to overide the root signature + /// used for the shader entry point. + std::string HLSLRootSigOverride; + // Indicates if the wasm-opt binary must be ignored in the case of a // WebAssembly target. bool NoWasmOpt = false; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 06bff0bf3b4ff..00dc6b4734e2b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -9436,6 +9436,13 @@ def dxc_rootsig_ver : Alias<fdx_rootsignature_version>, Group<dxc_Group>, Visibility<[DXCOption]>; +def fdx_rootsignature_define : + Joined<["-"], "fdx-rootsignature-define=">, + Group<dxc_Group>, + Visibility<[ClangOption, CC1Option]>, + MarshallingInfoString<LangOpts<"HLSLRootSigOverride">, "\"\"">, + HelpText<"Override entry function root signature with root signature at " + "given macro name.">; def hlsl_entrypoint : Option<["-"], "hlsl-entry", KIND_SEPARATE>, Group<dxc_Group>, Visibility<[ClangOption, CC1Option]>, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index da96352e1d82c..29f9cf3a7f0e3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -640,6 +640,10 @@ static bool FixupInvocation(CompilerInvocation &Invocation, Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fdx-rootsignature-version" << GetInputKindName(IK); + if (Args.hasArg(OPT_fdx_rootsignature_define) && !LangOpts.HLSL) + Diags.Report(diag::err_drv_argument_not_allowed_with) + << "-fdx-rootsignature-define" << GetInputKindName(IK); + if (Args.hasArg(OPT_fgpu_allow_device_init) && !LangOpts.HIP) Diags.Report(diag::warn_ignored_hip_only_option) << Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args); >From 2ebb085b14d24aa77972a901a9097373fdde4d57 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Wed, 20 Aug 2025 13:29:47 -0700 Subject: [PATCH 3/9] [Frontend][HLSL] Define `HLSLFrontendAction` to add a `PPCallback` --- .../clang/HLSL/Frontend/FrontendActions.h | 26 ++++++ clang/lib/CodeGen/CodeGenModule.cpp | 3 + clang/lib/Frontend/CMakeLists.txt | 1 + clang/lib/Frontend/HLSL/CMakeLists.txt | 14 +++ clang/lib/Frontend/HLSL/FrontendActions.cpp | 92 +++++++++++++++++++ clang/lib/FrontendTool/CMakeLists.txt | 1 + .../ExecuteCompilerInvocation.cpp | 5 + 7 files changed, 142 insertions(+) create mode 100644 clang/include/clang/HLSL/Frontend/FrontendActions.h create mode 100644 clang/lib/Frontend/HLSL/CMakeLists.txt create mode 100644 clang/lib/Frontend/HLSL/FrontendActions.cpp diff --git a/clang/include/clang/HLSL/Frontend/FrontendActions.h b/clang/include/clang/HLSL/Frontend/FrontendActions.h new file mode 100644 index 0000000000000..cbf00a3420dd2 --- /dev/null +++ b/clang/include/clang/HLSL/Frontend/FrontendActions.h @@ -0,0 +1,26 @@ +//===- HLSL/FrontendActions.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H +#define LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H + +#include "clang/Frontend/FrontendAction.h" + +namespace clang { + +class HLSLFrontendAction : public WrapperFrontendAction { +protected: + void ExecuteAction() override; + +public: + HLSLFrontendAction(std::unique_ptr<FrontendAction> WrappedAction); +}; + +} // namespace clang + +#endif // LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 677d8bc82cb0a..6e98213b81a9a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7534,6 +7534,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { getContext().getCanonicalTagType(cast<EnumDecl>(D))); break; + // Will be handled by attached function + case Decl::HLSLRootSignature: + break; case Decl::HLSLBuffer: getHLSLRuntime().addBuffer(cast<HLSLBufferDecl>(D)); break; diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index a916667208845..9f1806250345c 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(Rewrite) +add_subdirectory(HLSL) set(LLVM_LINK_COMPONENTS BitReader diff --git a/clang/lib/Frontend/HLSL/CMakeLists.txt b/clang/lib/Frontend/HLSL/CMakeLists.txt new file mode 100644 index 0000000000000..c09ee8ea55bc7 --- /dev/null +++ b/clang/lib/Frontend/HLSL/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(clangHLSLFrontend + FrontendActions.cpp + + LINK_LIBS + clangAST + clangBasic + clangFrontend + clangParse + clangSema + ) diff --git a/clang/lib/Frontend/HLSL/FrontendActions.cpp b/clang/lib/Frontend/HLSL/FrontendActions.cpp new file mode 100644 index 0000000000000..3365ac4b985be --- /dev/null +++ b/clang/lib/Frontend/HLSL/FrontendActions.cpp @@ -0,0 +1,92 @@ +//===--- FrontendActions.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/HLSL/Frontend/FrontendActions.h" +#include "clang/Parse/ParseHLSLRootSignature.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +class InjectRootSignatureCallback : public PPCallbacks { +private: + Sema &Actions; + StringRef RootSigName; + llvm::dxbc::RootSignatureVersion Version; + + std::optional<StringLiteral *> processStringLiteral(ArrayRef<Token> Tokens) { + for (Token Tok : Tokens) + if (!tok::isStringLiteral(Tok.getKind())) + return std::nullopt; + + ExprResult StringResult = Actions.ActOnUnevaluatedStringLiteral(Tokens); + if (StringResult.isInvalid()) + return std::nullopt; + + if (auto Signature = dyn_cast<StringLiteral>(StringResult.get())) + return Signature; + + return std::nullopt; + } + +public: + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + if (RootSigName != MacroNameTok.getIdentifierInfo()->getName()) + return; + + const MacroInfo *MI = MD->getMacroInfo(); + auto Signature = processStringLiteral(MI->tokens()); + if (!Signature.has_value()) { + Actions.getDiagnostics().Report(MI->getDefinitionLoc(), + diag::err_expected_string_literal) + << /*in attributes...*/ 4 << "RootSignature"; + return; + } + + IdentifierInfo *DeclIdent = + hlsl::ParseHLSLRootSignature(Actions, Version, *Signature); + } + + InjectRootSignatureCallback(Sema &Actions, StringRef RootSigName, + llvm::dxbc::RootSignatureVersion Version) + : PPCallbacks(), Actions(Actions), RootSigName(RootSigName), + Version(Version) {} +}; + +void HLSLFrontendAction::ExecuteAction() { + // Pre-requisites to invoke + CompilerInstance &CI = getCompilerInstance(); + if (!CI.hasASTContext() || !CI.hasPreprocessor()) + return WrapperFrontendAction::ExecuteAction(); + + // InjectRootSignatureCallback requires access to invoke Sema to lookup/ + // register a root signature declaration. The wrapped action is required to + // account for this by only creating a Sema if one doesn't already exist + // (like we have done, and, ASTFrontendAction::ExecuteAction) + if (!CI.hasSema()) + CI.createSema(getTranslationUnitKind(), + /*CodeCompleteConsumer=*/nullptr); + Sema &S = CI.getSema(); + + // Register HLSL specific callbacks + auto LangOpts = CI.getLangOpts(); + auto MacroCallback = std::make_unique<InjectRootSignatureCallback>( + S, LangOpts.HLSLRootSigOverride, LangOpts.HLSLRootSigVer); + + Preprocessor &PP = CI.getPreprocessor(); + PP.addPPCallbacks(std::move(MacroCallback)); + + // Invoke as normal + WrapperFrontendAction::ExecuteAction(); +} + +HLSLFrontendAction::HLSLFrontendAction( + std::unique_ptr<FrontendAction> WrappedAction) + : WrapperFrontendAction(std::move(WrappedAction)) {} + +} // namespace clang diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt index 061e54c3e62d0..ca760017f7e1d 100644 --- a/clang/lib/FrontendTool/CMakeLists.txt +++ b/clang/lib/FrontendTool/CMakeLists.txt @@ -10,6 +10,7 @@ set(link_libs clangExtractAPI clangFrontend clangRewriteFrontend + clangHLSLFrontend ) set(deps) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 443eb4f1a29bf..c3d52ad7a03ad 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -22,6 +22,7 @@ #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" +#include "clang/HLSL/Frontend/FrontendActions.h" #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" @@ -181,6 +182,10 @@ CreateFrontendAction(CompilerInstance &CI) { const FrontendOptions &FEOpts = CI.getFrontendOpts(); + if (CI.getLangOpts().HLSL) { + Act = std::make_unique<HLSLFrontendAction>(std::move(Act)); + } + if (FEOpts.FixAndRecompile) { Act = std::make_unique<FixItRecompile>(std::move(Act)); } >From 0406db0743982a331e55af22d4127a55f361831e Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Wed, 20 Aug 2025 13:30:13 -0700 Subject: [PATCH 4/9] [SemaHLSL] actually replace the entry function root signature --- clang/include/clang/Sema/SemaHLSL.h | 6 ++++++ clang/lib/Frontend/HLSL/FrontendActions.cpp | 1 + clang/lib/Sema/SemaHLSL.cpp | 17 +++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 016456f241eed..5cbe1b658f5cd 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -153,6 +153,10 @@ class SemaHLSL : public SemaBase { ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent, ArrayRef<hlsl::RootSignatureElement> Elements); + void SetRootSignatureOverride(IdentifierInfo *DeclIdent) { + RootSigOverrideIdent = DeclIdent; + } + // Returns true if any RootSignatureElement is invalid and a diagnostic was // produced bool @@ -221,6 +225,8 @@ class SemaHLSL : public SemaBase { uint32_t ImplicitBindingNextOrderID = 0; + IdentifierInfo *RootSigOverrideIdent = nullptr; + private: void collectResourceBindingsOnVarDecl(VarDecl *D); void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD, diff --git a/clang/lib/Frontend/HLSL/FrontendActions.cpp b/clang/lib/Frontend/HLSL/FrontendActions.cpp index 3365ac4b985be..c74e209a30401 100644 --- a/clang/lib/Frontend/HLSL/FrontendActions.cpp +++ b/clang/lib/Frontend/HLSL/FrontendActions.cpp @@ -50,6 +50,7 @@ class InjectRootSignatureCallback : public PPCallbacks { IdentifierInfo *DeclIdent = hlsl::ParseHLSLRootSignature(Actions, Version, *Signature); + Actions.HLSL().SetRootSignatureOverride(DeclIdent); } InjectRootSignatureCallback(Sema &Actions, StringRef RootSigName, diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f87715950c74c..29e092156010d 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -729,6 +729,23 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry) return; + // 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)); + } + } + llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment(); if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) { if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) { >From 8d47830e82a6215bf9f067f8bbf11e83c97d3d23 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Wed, 20 Aug 2025 14:28:56 -0700 Subject: [PATCH 5/9] testing --- .../AST/HLSL/rootsignature-define-ast.hlsl | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 clang/test/AST/HLSL/rootsignature-define-ast.hlsl diff --git a/clang/test/AST/HLSL/rootsignature-define-ast.hlsl b/clang/test/AST/HLSL/rootsignature-define-ast.hlsl new file mode 100644 index 0000000000000..9c17cbc9ad2eb --- /dev/null +++ b/clang/test/AST/HLSL/rootsignature-define-ast.hlsl @@ -0,0 +1,62 @@ +// Establish a baseline without define specified +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -ast-dump \ +// RUN: -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,NO-OVERRIDE + +// Check that we can set the entry function even if it doesn't have an attr +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -ast-dump \ +// RUN: -hlsl-entry none_main -fdx-rootsignature-define=SampleCBV \ +// RUN: -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,SET + +// Check that we can set the entry function overriding an attr +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -ast-dump \ +// RUN: -hlsl-entry uav_main -fdx-rootsignature-define=SampleCBV \ +// RUN: -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,OVERRIDE + +// Check that we can override with a command line root signature +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -ast-dump \ +// RUN: -hlsl-entry cbv_main -fdx-rootsignature-define=CmdRS -DCmdRS='"SRV(t0)"' \ +// RUN: -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CMD + +#define SampleCBV "CBV(b0)" +#define SampleUAV "UAV(u0)" + +// CMD: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[CMD_DECL:__hlsl_rootsig_decl_\d*]] +// CMD-SAME: version: 1.1, RootElements{ +// CMD-SAME: RootSRV(t0, +// CMD-SAME: space = 0, visibility = All, flags = DataStaticWhileSetAtExecute +// CMD-SAME: )} + +// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[CBV_DECL:__hlsl_rootsig_decl_\d*]] +// CHECK-SAME: version: 1.1, RootElements{ +// CHECK-SAME: RootCBV(b0, +// CHECK-SAME: space = 0, visibility = All, flags = DataStaticWhileSetAtExecute +// CHECK-SAME: )} + +// CHECK-LABEL: -FunctionDecl 0x{{.*}} {{.*}} cbv_main +// NO-OVERRIDE: -RootSignatureAttr 0x{{.*}} {{.*}} [[CBV_DECL]] +// SET: -RootSignatureAttr 0x{{.*}} {{.*}} [[CBV_DECL]] +// CMD: -RootSignatureAttr 0x{{.*}} {{.*}} [[CMD_DECL]] + +[RootSignature(SampleCBV)] +void cbv_main() {} + +// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[UAV_DECL:__hlsl_rootsig_decl_\d*]] +// CHECK-SAME: version: 1.1, RootElements{ +// CHECK-SAME: RootUAV(u0, +// CHECK-SAME: space = 0, visibility = All, flags = DataVolatile +// CHECK-SAME: )} + +// CHECK-LABEL: -FunctionDecl 0x{{.*}} {{.*}} uav_main +// NO-OVERRIDE: -RootSignatureAttr 0x{{.*}} {{.*}} [[UAV_DECL]] +// SET: -RootSignatureAttr 0x{{.*}} {{.*}} [[UAV_DECL]] +// OVERRIDE: -RootSignatureAttr 0x{{.*}} {{.*}} [[CBV_DECL]] + +[RootSignature(SampleUAV)] +void uav_main() {} + +// CHECK-LABEL: -FunctionDecl 0x{{.*}} {{.*}} none_main +// NO-OVERRIDE-NONE: -RootSignatureAttr +// SET: -RootSignatureAttr 0x{{.*}} {{.*}} [[CBV_DECL]] +// OVERRIDE-NONE: -RootSignatureAttr + +void none_main() {} >From ec96787907e40b5b8041931a0afeb29a3aca85e6 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Wed, 20 Aug 2025 14:29:37 -0700 Subject: [PATCH 6/9] [Driver][DXC] add `rootsig-define` as an alias option --- clang/include/clang/Driver/Options.td | 5 +++++ clang/lib/Driver/ToolChains/Clang.cpp | 1 + clang/lib/Driver/ToolChains/HLSL.cpp | 7 +++++++ clang/test/Driver/dxc_rootsig-define.hlsl | 21 +++++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 clang/test/Driver/dxc_rootsig-define.hlsl diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 00dc6b4734e2b..291eb26482551 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -9443,6 +9443,11 @@ def fdx_rootsignature_define : MarshallingInfoString<LangOpts<"HLSLRootSigOverride">, "\"\"">, HelpText<"Override entry function root signature with root signature at " "given macro name.">; +def dxc_rootsig_define : + Separate<["-"], "rootsig-define">, + Alias<fdx_rootsignature_define>, + Group<dxc_Group>, + Visibility<[DXCOption]>; def hlsl_entrypoint : Option<["-"], "hlsl-entry", KIND_SEPARATE>, Group<dxc_Group>, Visibility<[ClangOption, CC1Option]>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 29b7180df5cb5..f3ac4ee1b3c77 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3801,6 +3801,7 @@ static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs, options::OPT_disable_llvm_passes, options::OPT_fnative_half_type, options::OPT_hlsl_entrypoint, + options::OPT_fdx_rootsignature_define, options::OPT_fdx_rootsignature_version}; if (!types::isHLSL(InputType)) return; diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 38f4643abad98..570c5c86246d4 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -304,6 +304,13 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, A->claim(); continue; } + if (A->getOption().getID() == options::OPT_dxc_rootsig_define) { + DAL->AddJoinedArg(nullptr, + Opts.getOption(options::OPT_fdx_rootsignature_define), + A->getValue()); + A->claim(); + continue; + } if (A->getOption().getID() == options::OPT__SLASH_O) { StringRef OStr = A->getValue(); if (OStr == "d") { diff --git a/clang/test/Driver/dxc_rootsig-define.hlsl b/clang/test/Driver/dxc_rootsig-define.hlsl new file mode 100644 index 0000000000000..21594077dfdf8 --- /dev/null +++ b/clang/test/Driver/dxc_rootsig-define.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_dxc -T cs_6_0 -fcgl %s | FileCheck %s --check-prefixes=CHECK,REG +// RUN: %clang_dxc -T cs_6_0 -fcgl -rootsig-define EmptyRS %s | FileCheck %s --check-prefixes=CHECK,EMPTY +// RUN: %clang_dxc -T cs_6_0 -fcgl -rootsig-define CmdRS -D CmdRS='"SRV(t0)"' %s | FileCheck %s --check-prefixes=CHECK,CMD + +#define EmptyRS "" +#define NotEmptyRS "CBV(b0)" + +// CHECK: !dx.rootsignatures = !{![[#ENTRY:]]} +// CHECK: ![[#ENTRY]] = !{ptr @main, ![[#RS:]], i32 2} + +// REG: ![[#RS]] = !{![[#CBV:]]} +// REG: ![[#CBV]] = !{!"RootCBV" + +// EMPTY: ![[#RS]] = !{} + +// CMD: ![[#RS]] = !{![[#SRV:]]} +// CMD: ![[#SRV]] = !{!"RootSRV" + +[shader("compute"), RootSignature(NotEmptyRS)] +[numthreads(1,1,1)] +void main() {} >From e691dd3899ca7584b3bdc057f32f11f743614946 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Thu, 21 Aug 2025 12:30:41 -0700 Subject: [PATCH 7/9] review: remove custom `Frontend/HLSL` library - moves the define `HLSLFrontendAction` to `clang/Frontend/FrontendActions` --- .../include/clang/Frontend/FrontendActions.h | 12 +++ .../clang/HLSL/Frontend/FrontendActions.h | 26 ------ clang/lib/Frontend/CMakeLists.txt | 1 - clang/lib/Frontend/FrontendActions.cpp | 83 +++++++++++++++++ clang/lib/Frontend/HLSL/CMakeLists.txt | 14 --- clang/lib/Frontend/HLSL/FrontendActions.cpp | 93 ------------------- clang/lib/FrontendTool/CMakeLists.txt | 1 - .../ExecuteCompilerInvocation.cpp | 1 - 8 files changed, 95 insertions(+), 136 deletions(-) delete mode 100644 clang/include/clang/HLSL/Frontend/FrontendActions.h delete mode 100644 clang/lib/Frontend/HLSL/CMakeLists.txt delete mode 100644 clang/lib/Frontend/HLSL/FrontendActions.cpp diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index a5dfb770c58a2..73308c004bd23 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -329,6 +329,18 @@ class GetDependenciesByModuleNameAction : public PreprocessOnlyAction { : ModuleName(ModuleName) {} }; +//===----------------------------------------------------------------------===// +// HLSL Specific Actions +//===----------------------------------------------------------------------===// + +class HLSLFrontendAction : public WrapperFrontendAction { +protected: + void ExecuteAction() override; + +public: + HLSLFrontendAction(std::unique_ptr<FrontendAction> WrappedAction); +}; + } // end namespace clang #endif diff --git a/clang/include/clang/HLSL/Frontend/FrontendActions.h b/clang/include/clang/HLSL/Frontend/FrontendActions.h deleted file mode 100644 index cbf00a3420dd2..0000000000000 --- a/clang/include/clang/HLSL/Frontend/FrontendActions.h +++ /dev/null @@ -1,26 +0,0 @@ -//===- HLSL/FrontendActions.h -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H -#define LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H - -#include "clang/Frontend/FrontendAction.h" - -namespace clang { - -class HLSLFrontendAction : public WrapperFrontendAction { -protected: - void ExecuteAction() override; - -public: - HLSLFrontendAction(std::unique_ptr<FrontendAction> WrappedAction); -}; - -} // namespace clang - -#endif // LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index 9f1806250345c..a916667208845 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -1,5 +1,4 @@ add_subdirectory(Rewrite) -add_subdirectory(HLSL) set(LLVM_LINK_COMPONENTS BitReader diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 685a9bbf2cde9..ccda2c4ce4b6d 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -22,6 +22,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Parse/ParseHLSLRootSignature.h" #include "clang/Sema/TemplateInstCallback.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" @@ -1241,3 +1242,85 @@ void GetDependenciesByModuleNameAction::ExecuteAction() { PPCallbacks *CB = PP.getPPCallbacks(); CB->moduleImport(SourceLocation(), Path, ModResult); } + +//===----------------------------------------------------------------------===// +// HLSL Specific Actions +//===----------------------------------------------------------------------===// + +class InjectRootSignatureCallback : public PPCallbacks { +private: + Sema &Actions; + StringRef RootSigName; + llvm::dxbc::RootSignatureVersion Version; + + std::optional<StringLiteral *> processStringLiteral(ArrayRef<Token> Tokens) { + for (Token Tok : Tokens) + if (!tok::isStringLiteral(Tok.getKind())) + return std::nullopt; + + ExprResult StringResult = Actions.ActOnUnevaluatedStringLiteral(Tokens); + if (StringResult.isInvalid()) + return std::nullopt; + + if (auto Signature = dyn_cast<StringLiteral>(StringResult.get())) + return Signature; + + return std::nullopt; + } + +public: + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + if (RootSigName != MacroNameTok.getIdentifierInfo()->getName()) + return; + + const MacroInfo *MI = MD->getMacroInfo(); + auto Signature = processStringLiteral(MI->tokens()); + if (!Signature.has_value()) { + Actions.getDiagnostics().Report(MI->getDefinitionLoc(), + diag::err_expected_string_literal) + << /*in attributes...*/ 4 << "RootSignature"; + return; + } + + IdentifierInfo *DeclIdent = + hlsl::ParseHLSLRootSignature(Actions, Version, *Signature); + Actions.HLSL().SetRootSignatureOverride(DeclIdent); + } + + InjectRootSignatureCallback(Sema &Actions, StringRef RootSigName, + llvm::dxbc::RootSignatureVersion Version) + : PPCallbacks(), Actions(Actions), RootSigName(RootSigName), + Version(Version) {} +}; + +void HLSLFrontendAction::ExecuteAction() { + // Pre-requisites to invoke + CompilerInstance &CI = getCompilerInstance(); + if (!CI.hasASTContext() || !CI.hasPreprocessor()) + return WrapperFrontendAction::ExecuteAction(); + + // InjectRootSignatureCallback requires access to invoke Sema to lookup/ + // register a root signature declaration. The wrapped action is required to + // account for this by only creating a Sema if one doesn't already exist + // (like we have done, and, ASTFrontendAction::ExecuteAction) + if (!CI.hasSema()) + CI.createSema(getTranslationUnitKind(), + /*CodeCompleteConsumer=*/nullptr); + Sema &S = CI.getSema(); + + // Register HLSL specific callbacks + auto LangOpts = CI.getLangOpts(); + auto MacroCallback = std::make_unique<InjectRootSignatureCallback>( + S, LangOpts.HLSLRootSigOverride, LangOpts.HLSLRootSigVer); + + Preprocessor &PP = CI.getPreprocessor(); + PP.addPPCallbacks(std::move(MacroCallback)); + + // Invoke as normal + WrapperFrontendAction::ExecuteAction(); +} + +HLSLFrontendAction::HLSLFrontendAction( + std::unique_ptr<FrontendAction> WrappedAction) + : WrapperFrontendAction(std::move(WrappedAction)) {} diff --git a/clang/lib/Frontend/HLSL/CMakeLists.txt b/clang/lib/Frontend/HLSL/CMakeLists.txt deleted file mode 100644 index c09ee8ea55bc7..0000000000000 --- a/clang/lib/Frontend/HLSL/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Support - ) - -add_clang_library(clangHLSLFrontend - FrontendActions.cpp - - LINK_LIBS - clangAST - clangBasic - clangFrontend - clangParse - clangSema - ) diff --git a/clang/lib/Frontend/HLSL/FrontendActions.cpp b/clang/lib/Frontend/HLSL/FrontendActions.cpp deleted file mode 100644 index c74e209a30401..0000000000000 --- a/clang/lib/Frontend/HLSL/FrontendActions.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===--- FrontendActions.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "clang/HLSL/Frontend/FrontendActions.h" -#include "clang/Parse/ParseHLSLRootSignature.h" -#include "clang/Sema/Sema.h" - -namespace clang { - -class InjectRootSignatureCallback : public PPCallbacks { -private: - Sema &Actions; - StringRef RootSigName; - llvm::dxbc::RootSignatureVersion Version; - - std::optional<StringLiteral *> processStringLiteral(ArrayRef<Token> Tokens) { - for (Token Tok : Tokens) - if (!tok::isStringLiteral(Tok.getKind())) - return std::nullopt; - - ExprResult StringResult = Actions.ActOnUnevaluatedStringLiteral(Tokens); - if (StringResult.isInvalid()) - return std::nullopt; - - if (auto Signature = dyn_cast<StringLiteral>(StringResult.get())) - return Signature; - - return std::nullopt; - } - -public: - void MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) override { - if (RootSigName != MacroNameTok.getIdentifierInfo()->getName()) - return; - - const MacroInfo *MI = MD->getMacroInfo(); - auto Signature = processStringLiteral(MI->tokens()); - if (!Signature.has_value()) { - Actions.getDiagnostics().Report(MI->getDefinitionLoc(), - diag::err_expected_string_literal) - << /*in attributes...*/ 4 << "RootSignature"; - return; - } - - IdentifierInfo *DeclIdent = - hlsl::ParseHLSLRootSignature(Actions, Version, *Signature); - Actions.HLSL().SetRootSignatureOverride(DeclIdent); - } - - InjectRootSignatureCallback(Sema &Actions, StringRef RootSigName, - llvm::dxbc::RootSignatureVersion Version) - : PPCallbacks(), Actions(Actions), RootSigName(RootSigName), - Version(Version) {} -}; - -void HLSLFrontendAction::ExecuteAction() { - // Pre-requisites to invoke - CompilerInstance &CI = getCompilerInstance(); - if (!CI.hasASTContext() || !CI.hasPreprocessor()) - return WrapperFrontendAction::ExecuteAction(); - - // InjectRootSignatureCallback requires access to invoke Sema to lookup/ - // register a root signature declaration. The wrapped action is required to - // account for this by only creating a Sema if one doesn't already exist - // (like we have done, and, ASTFrontendAction::ExecuteAction) - if (!CI.hasSema()) - CI.createSema(getTranslationUnitKind(), - /*CodeCompleteConsumer=*/nullptr); - Sema &S = CI.getSema(); - - // Register HLSL specific callbacks - auto LangOpts = CI.getLangOpts(); - auto MacroCallback = std::make_unique<InjectRootSignatureCallback>( - S, LangOpts.HLSLRootSigOverride, LangOpts.HLSLRootSigVer); - - Preprocessor &PP = CI.getPreprocessor(); - PP.addPPCallbacks(std::move(MacroCallback)); - - // Invoke as normal - WrapperFrontendAction::ExecuteAction(); -} - -HLSLFrontendAction::HLSLFrontendAction( - std::unique_ptr<FrontendAction> WrappedAction) - : WrapperFrontendAction(std::move(WrappedAction)) {} - -} // namespace clang diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt index ca760017f7e1d..061e54c3e62d0 100644 --- a/clang/lib/FrontendTool/CMakeLists.txt +++ b/clang/lib/FrontendTool/CMakeLists.txt @@ -10,7 +10,6 @@ set(link_libs clangExtractAPI clangFrontend clangRewriteFrontend - clangHLSLFrontend ) set(deps) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index c3d52ad7a03ad..7d7521e7f4e43 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -22,7 +22,6 @@ #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" -#include "clang/HLSL/Frontend/FrontendActions.h" #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" >From b08b3acc49f665a224a65391a9ab628d05b7c7db Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Thu, 21 Aug 2025 12:36:19 -0700 Subject: [PATCH 8/9] review: style guide --- clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 7d7521e7f4e43..9a6844d5f7d40 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -181,9 +181,8 @@ CreateFrontendAction(CompilerInstance &CI) { const FrontendOptions &FEOpts = CI.getFrontendOpts(); - if (CI.getLangOpts().HLSL) { + if (CI.getLangOpts().HLSL) Act = std::make_unique<HLSLFrontendAction>(std::move(Act)); - } if (FEOpts.FixAndRecompile) { Act = std::make_unique<FixItRecompile>(std::move(Act)); >From 137bd96c6d3c37e8cf1df315a3b6139ea3919f46 Mon Sep 17 00:00:00 2001 From: Finn Plummer <m...@inbelic.dev> Date: Thu, 21 Aug 2025 12:48:12 -0700 Subject: [PATCH 9/9] review: add clang checks --- clang/test/Driver/dxc_rootsig-define.hlsl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/test/Driver/dxc_rootsig-define.hlsl b/clang/test/Driver/dxc_rootsig-define.hlsl index 21594077dfdf8..40c3e127f94d5 100644 --- a/clang/test/Driver/dxc_rootsig-define.hlsl +++ b/clang/test/Driver/dxc_rootsig-define.hlsl @@ -2,6 +2,18 @@ // RUN: %clang_dxc -T cs_6_0 -fcgl -rootsig-define EmptyRS %s | FileCheck %s --check-prefixes=CHECK,EMPTY // RUN: %clang_dxc -T cs_6_0 -fcgl -rootsig-define CmdRS -D CmdRS='"SRV(t0)"' %s | FileCheck %s --check-prefixes=CHECK,CMD +// Equivalent clang checks: +// RUN: %clang -target dxil-unknown-shadermodel6.0-compute -S -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK,REG + +// RUN: %clang -target dxil-unknown-shadermodel6.0-compute -S -emit-llvm -o - %s \ +// RUN: -fdx-rootsignature-define=EmptyRS \ +// RUN: | FileCheck %s --check-prefixes=CHECK,EMPTY + +// RUN: %clang -target dxil-unknown-shadermodel6.0-compute -S -emit-llvm -o - %s \ +// RUN: -fdx-rootsignature-define=CmdRS -D CmdRS='"SRV(t0)"' \ +// RUN: | FileCheck %s --check-prefixes=CHECK,CMD + #define EmptyRS "" #define NotEmptyRS "CBV(b0)" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits