-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[HLSL][RootSignature] Introduce HLSLFrontendAction
to implement rootsig-define
#154639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang-driver Author: Finn Plummer (inbelic) ChangesThis pr implements the functionality of This is accomplished by:
Resolves #150274 Implementation considerationsTo implement this feature, note:
This that we can't handle the root signature in This means we could alternatively:
The proposed solution handles this in the most modular way which should work on any Patch is 20.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154639.diff 19 Files Affected:
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..291eb26482551 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9436,6 +9436,18 @@ 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 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/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/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/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/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/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/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/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);
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..c74e209a30401
--- /dev/null
+++ b/clang/lib/Frontend/HLSL/FrontendActions.cpp
@@ -0,0 +1,93 @@
+//===--- 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 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));
}
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
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>()) {
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() {}
di...
[truncated]
|
@llvm/pr-subscribers-hlsl Author: Finn Plummer (inbelic) ChangesThis pr implements the functionality of This is accomplished by:
Resolves #150274 Implementation considerationsTo implement this feature, note:
This that we can't handle the root signature in This means we could alternatively:
The proposed solution handles this in the most modular way which should work on any Patch is 20.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154639.diff 19 Files Affected:
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..291eb26482551 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9436,6 +9436,18 @@ 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 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/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/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/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/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/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/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/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);
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..c74e209a30401
--- /dev/null
+++ b/clang/lib/Frontend/HLSL/FrontendActions.cpp
@@ -0,0 +1,93 @@
+//===--- 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 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));
}
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
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>()) {
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() {}
di...
[truncated]
|
@llvm/pr-subscribers-clang Author: Finn Plummer (inbelic) ChangesThis pr implements the functionality of This is accomplished by:
Resolves #150274 Implementation considerationsTo implement this feature, note:
This that we can't handle the root signature in This means we could alternatively:
The proposed solution handles this in the most modular way which should work on any Patch is 20.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154639.diff 19 Files Affected:
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..291eb26482551 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9436,6 +9436,18 @@ 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 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/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/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/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/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/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/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/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);
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..c74e209a30401
--- /dev/null
+++ b/clang/lib/Frontend/HLSL/FrontendActions.cpp
@@ -0,0 +1,93 @@
+//===--- 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 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));
}
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
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>()) {
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() {}
di...
[truncated]
|
def fdx_rootsignature_define : | ||
Joined<["-"], "fdx-rootsignature-define=">, | ||
Group<dxc_Group>, | ||
Visibility<[ClangOption, CC1Option]>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exposing this as a Clang option and not just a CC1 option is an interesting choice. I think I like it since I'd like us to someday move away from the DXC driver, but is this a conscious decision? I don't recall that in the proposal (https://github.com/llvm/wg-hlsl/blob/main/proposals/0029-root-signature-driver-options.md).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was under the impression that in general we were adding these to clang as well, see hlsl-entry
, dxil-validator-version
, dx_rootsignature_version
, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have no tests that actually test that, I'm going to guess that's a copypasta mistake, not an intentional design decision. That said I'm okay leaving this as-is.
) | ||
|
||
add_clang_library(clangHLSLFrontend | ||
FrontendActions.cpp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was feedback provided somewhere to put this in its own library? I don't expect that we'll have a lot of unique HLSL Frontend options and I'm unsure this is really necessary since it isn't really a separable component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No feedback to, I had just been following Frontend/Rewrite/FrontendActions
.
I will move this to clang/FrontendAction/FrontendActions.[h|cpp]
.
- moves the define `HLSLFrontendAction` to `clang/Frontend/FrontendActions`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
Co-authored-by: Deric C. <cheung.deric@gmail.com>
This pr implements the functionality of
rootsig-define
as described here.This is accomplished by:
fdx-rootsignature-define
, androotsig-define
alias, driver options. It simply specifies the name of a macro that will expand to aLiteralString
to be interpreted as a root signature.HLSLFrontendAction
. This class allows us to introduceHLSL
specific behaviour on the underlying action (primarilyASTFrontendAction
). Which will be further extended, or modularly wrapped, when considering future DXC options.HLSLFrontendAction
we can add a newPPCallback
that will eagerly parse the root signature specified withrootsig-define
and push it as aTopLevelDecl
toSema
. This occurs when the macro has been lexed.Resolves #150274
Implementation considerations
To implement this feature, note that:
Lex
inParser::Initialize
afterPP->EnterMainSourceFile
RootSignatureDecl
must be added toSema
beforeConsumer->HandleTranslationUnit
is invoked inParseAST
Therefore, we can't handle the root signature in
HLSLFrontendAction::ExecuteAction
before (from 1.) or after (from 2.) invoking the underlyingASTFrontendAction
.This means we could alternatively:
RootSignatureAttr
.The proposed solution handles this in the most modular way which should work on any
FrontendAction
that might use theParser
without invokingParseAST
, and, is not subject to needing to call the hook in multiple different places of function declarators.