[llvm] ad49111 - [HLSL][DirectX] Add support for `rootsig` as a target environment (#156373)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 9 08:15:03 PDT 2025
Author: Finn Plummer
Date: 2025-09-09T09:14:58-06:00
New Revision: ad491118df1304c7d6bcce5b2207895f57204c16
URL: https://github.com/llvm/llvm-project/commit/ad491118df1304c7d6bcce5b2207895f57204c16
DIFF: https://github.com/llvm/llvm-project/commit/ad491118df1304c7d6bcce5b2207895f57204c16.diff
LOG: [HLSL][DirectX] Add support for `rootsig` as a target environment (#156373)
This pr implements support for a root signature as a target, as specified
[here](https://github.com/llvm/wg-hlsl/blob/main/proposals/0029-root-signature-driver-options.md#target-root-signature-version).
This is implemented in the following steps:
1. Add `rootsignature` as a shader model environment type and define
`rootsig` as a `target_profile`. Only valid as versions 1.0 and 1.1
2. Updates `HLSLFrontendAction` to invoke a special handling of
constructing the `ASTContext` if we are considering an `hlsl` file and
with a `rootsignature` target
3. Defines the special handling to minimally instantiate the `Parser`
and `Sema` to insert the `RootSignatureDecl`
4. Updates `CGHLSLRuntime` to emit the constructed root signature decl
as part of `dx.rootsignatures` with a `null` entry function
5. Updates `DXILRootSignature` to handle emitting a root signature
without an entry function
6. Updates `ToolChains/HLSL` to invoke `only-section=RTS0` to strip any
other generated information
Resolves: https://github.com/llvm/llvm-project/issues/150286.
##### Implementation Considerations
Ideally we could invoke this as part of `clang-dxc` without the need of
a source file. However, the initialization of the `Parser` and `Lexer`
becomes quite complicated to handle this.
Technically, we could avoid generating any of the extra information that
is removed in step 6. However, it seems better to re-use the logic in
`llvm-objcopy` without any need for additional custom logic in
`DXILRootSignature`.
Added:
clang/test/AST/HLSL/RootSignature-Target-AST.hlsl
clang/test/CodeGenHLSL/RootSignature-Target.hlsl
clang/test/Driver/dxc_rootsignature_target.hlsl
clang/test/SemaHLSL/RootSignature-target-err.hlsl
llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll
Modified:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Driver/Options.td
clang/include/clang/Parse/ParseHLSLRootSignature.h
clang/include/clang/Sema/SemaHLSL.h
clang/lib/CodeGen/CGHLSLRuntime.cpp
clang/lib/CodeGen/CGHLSLRuntime.h
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/Driver/ToolChains/HLSL.cpp
clang/lib/Frontend/FrontendActions.cpp
clang/lib/Parse/ParseHLSLRootSignature.cpp
clang/lib/Sema/SemaHLSL.cpp
llvm/include/llvm/BinaryFormat/DXContainer.h
llvm/include/llvm/TargetParser/Triple.h
llvm/lib/Target/DirectX/DXContainerGlobals.cpp
llvm/lib/Target/DirectX/DXILRootSignature.cpp
llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
llvm/lib/TargetParser/Triple.cpp
llvm/unittests/TargetParser/TripleTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fdf6e3a2a926b..b85abfcbecfcf 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1195,6 +1195,7 @@ static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environm
.Case("callable", llvm::Triple::Callable)
.Case("mesh", llvm::Triple::Mesh)
.Case("amplification", llvm::Triple::Amplification)
+ .Case("rootsignature", llvm::Triple::RootSignature)
.Case("library", llvm::Triple::Library)
.Default(llvm::Triple::UnknownEnvironment);
}
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1a4ebc11119a5..e69123bb3715d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13152,6 +13152,8 @@ def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used on
def err_hlsl_incorrect_num_initializers: Error<
"too %select{few|many}0 initializers in list for type %1 "
"(expected %2 but found %3)">;
+def err_hlsl_rootsignature_entry: Error<
+ "rootsignature specified as target environment but entry, %0, was not defined">;
def err_hlsl_operator_unsupported : Error<
"the '%select{&|*|->}0' operator is unsupported in HLSL">;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index ea5a94f840470..cc68348d04413 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9444,7 +9444,8 @@ def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
"cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, cs_6_7,"
"lib_6_3, lib_6_4, lib_6_5, lib_6_6, lib_6_7, lib_6_x,"
"ms_6_5, ms_6_6, ms_6_7,"
- "as_6_5, as_6_6, as_6_7">;
+ "as_6_5, as_6_6, as_6_7,"
+ "rootsig_1_0, rootsig_1_1">;
def emit_pristine_llvm : DXCFlag<"emit-pristine-llvm">,
HelpText<"Emit pristine LLVM IR from the frontend by not running any LLVM passes at all."
"Same as -S + -emit-llvm + -disable-llvm-passes.">;
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index c87e6637c7fce..b06846fd83c09 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -240,6 +240,8 @@ IdentifierInfo *ParseHLSLRootSignature(Sema &Actions,
llvm::dxbc::RootSignatureVersion Version,
StringLiteral *Signature);
+void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig);
+
} // namespace hlsl
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 9aa0812b07314..b5ddca0fe2ca5 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -159,6 +159,8 @@ class SemaHLSL : public SemaBase {
RootSigOverrideIdent = DeclIdent;
}
+ HLSLRootSignatureDecl *lookupRootSignatureOverrideDecl(DeclContext *DC) const;
+
// Returns true if any RootSignatureElement is invalid and a diagnostic was
// produced
bool
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 0177733c83be2..afee1198e0988 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -70,9 +70,9 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
DXILValMD->addOperand(Val);
}
-void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer,
- ArrayRef<llvm::hlsl::rootsig::RootElement> Elements,
- llvm::Function *Fn, llvm::Module &M) {
+void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
+ ArrayRef<llvm::hlsl::rootsig::RootElement> Elements,
+ llvm::Function *Fn, llvm::Module &M) {
auto &Ctx = M.getContext();
llvm::hlsl::rootsig::MetadataBuilder RSBuilder(Ctx, Elements);
@@ -80,8 +80,8 @@ void addRootSignature(llvm::dxbc::RootSignatureVersion RootSigVer,
ConstantAsMetadata *Version = ConstantAsMetadata::get(ConstantInt::get(
llvm::Type::getInt32Ty(Ctx), llvm::to_underlying(RootSigVer)));
- MDNode *MDVals =
- MDNode::get(Ctx, {ValueAsMetadata::get(Fn), RootSignature, Version});
+ ValueAsMetadata *EntryFunc = Fn ? ValueAsMetadata::get(Fn) : nullptr;
+ MDNode *MDVals = MDNode::get(Ctx, {EntryFunc, RootSignature, Version});
StringRef RootSignatureValKey = "dx.rootsignatures";
auto *RootSignatureValMD = M.getOrInsertNamedMetadata(RootSignatureValKey);
@@ -449,6 +449,19 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
}
}
+void CGHLSLRuntime::addRootSignature(
+ const HLSLRootSignatureDecl *SignatureDecl) {
+ llvm::Module &M = CGM.getModule();
+ Triple T(M.getTargetTriple());
+
+ // Generated later with the function decl if not targeting root signature
+ if (T.getEnvironment() != Triple::EnvironmentType::RootSignature)
+ return;
+
+ addRootSignatureMD(SignatureDecl->getVersion(),
+ SignatureDecl->getRootElements(), nullptr, M);
+}
+
llvm::TargetExtType *
CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
const auto Entry = LayoutTypes.find(StructType);
@@ -685,8 +698,8 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
for (const Attr *Attr : FD->getAttrs()) {
if (const auto *RSAttr = dyn_cast<RootSignatureAttr>(Attr)) {
auto *RSDecl = RSAttr->getSignatureDecl();
- addRootSignature(RSDecl->getVersion(), RSDecl->getRootElements(), EntryFn,
- M);
+ addRootSignatureMD(RSDecl->getVersion(), RSDecl->getRootElements(),
+ EntryFn, M);
}
}
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 25d4c65426b0d..370f3d5c5d30d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -64,6 +64,7 @@ class VarDecl;
class ParmVarDecl;
class InitListExpr;
class HLSLBufferDecl;
+class HLSLRootSignatureDecl;
class HLSLVkBindingAttr;
class HLSLResourceBindingAttr;
class Type;
@@ -171,6 +172,7 @@ class CGHLSLRuntime {
void generateGlobalCtorDtorCalls();
void addBuffer(const HLSLBufferDecl *D);
+ void addRootSignature(const HLSLRootSignatureDecl *D);
void finishCodeGen();
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 87d2cd4ce468d..5e96f5bd6e5f8 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -7545,7 +7545,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
case Decl::HLSLRootSignature:
- // Will be handled by attached function
+ getHLSLRuntime().addRootSignature(cast<HLSLRootSignatureDecl>(D));
break;
case Decl::HLSLBuffer:
getHLSLRuntime().addBuffer(cast<HLSLBufferDecl>(D));
diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp
index 559af32dc3808..b36297c169376 100644
--- a/clang/lib/Driver/ToolChains/HLSL.cpp
+++ b/clang/lib/Driver/ToolChains/HLSL.cpp
@@ -62,11 +62,15 @@ bool isLegalShaderModel(Triple &T) {
VersionTuple MinVer(6, 5);
return MinVer <= Version;
} break;
+ case Triple::EnvironmentType::RootSignature:
+ VersionTuple MinVer(1, 0);
+ VersionTuple MaxVer(1, 1);
+ return MinVer <= Version && Version <= MaxVer;
}
return false;
}
-std::optional<std::string> tryParseProfile(StringRef Profile) {
+std::optional<llvm::Triple> tryParseTriple(StringRef Profile) {
// [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
SmallVector<StringRef, 3> Parts;
Profile.split(Parts, "_");
@@ -84,6 +88,7 @@ std::optional<std::string> tryParseProfile(StringRef Profile) {
.Case("lib", Triple::EnvironmentType::Library)
.Case("ms", Triple::EnvironmentType::Mesh)
.Case("as", Triple::EnvironmentType::Amplification)
+ .Case("rootsig", Triple::EnvironmentType::RootSignature)
.Default(Triple::EnvironmentType::UnknownEnvironment);
if (Kind == Triple::EnvironmentType::UnknownEnvironment)
return std::nullopt;
@@ -147,8 +152,14 @@ std::optional<std::string> tryParseProfile(StringRef Profile) {
T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() +
VersionTuple(Major, Minor).getAsString());
T.setEnvironment(Kind);
- if (isLegalShaderModel(T))
- return T.getTriple();
+
+ return T;
+}
+
+std::optional<std::string> tryParseProfile(StringRef Profile) {
+ std::optional<llvm::Triple> MaybeT = tryParseTriple(Profile);
+ if (MaybeT && isLegalShaderModel(*MaybeT))
+ return MaybeT->getTriple();
else
return std::nullopt;
}
@@ -258,6 +269,19 @@ bool checkExtensionArgsAreValid(ArrayRef<std::string> SpvExtensionArgs,
}
return AllValid;
}
+
+bool isRootSignatureTarget(StringRef Profile) {
+ if (std::optional<llvm::Triple> T = tryParseTriple(Profile))
+ return T->getEnvironment() == Triple::EnvironmentType::RootSignature;
+ return false;
+}
+
+bool isRootSignatureTarget(DerivedArgList &Args) {
+ if (const Arg *A = Args.getLastArg(options::OPT_target_profile))
+ return isRootSignatureTarget(A->getValue());
+ return false;
+}
+
} // namespace
void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA,
@@ -317,6 +341,12 @@ void tools::hlsl::LLVMObjcopy::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Frs);
}
+ if (const Arg *A = Args.getLastArg(options::OPT_target_profile))
+ if (isRootSignatureTarget(A->getValue())) {
+ const char *Fos = Args.MakeArgString("--only-section=RTS0");
+ CmdArgs.push_back(Fos);
+ }
+
assert(CmdArgs.size() > 2 && "Unnecessary invocation of objcopy.");
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
@@ -493,7 +523,8 @@ bool HLSLToolChain::requiresBinaryTranslation(DerivedArgList &Args) const {
bool HLSLToolChain::requiresObjcopy(DerivedArgList &Args) const {
return Args.hasArg(options::OPT_dxc_Fo) &&
- Args.hasArg(options::OPT_dxc_strip_rootsignature);
+ (Args.hasArg(options::OPT_dxc_strip_rootsignature) ||
+ isRootSignatureTarget(Args));
}
bool HLSLToolChain::isLastJob(DerivedArgList &Args,
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index f18318478d7a7..7424958d46612 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -1310,16 +1310,27 @@ void HLSLFrontendAction::ExecuteAction() {
/*CodeCompleteConsumer=*/nullptr);
Sema &S = CI.getSema();
+ auto &TargetInfo = CI.getASTContext().getTargetInfo();
+ bool IsRootSignatureTarget =
+ TargetInfo.getTriple().getEnvironment() == llvm::Triple::RootSignature;
+ StringRef HLSLEntry = TargetInfo.getTargetOpts().HLSLEntry;
+
// Register HLSL specific callbacks
auto LangOpts = CI.getLangOpts();
+ StringRef RootSigName =
+ IsRootSignatureTarget ? HLSLEntry : LangOpts.HLSLRootSigOverride;
+
auto MacroCallback = std::make_unique<InjectRootSignatureCallback>(
- S, LangOpts.HLSLRootSigOverride, LangOpts.HLSLRootSigVer);
+ S, RootSigName, LangOpts.HLSLRootSigVer);
Preprocessor &PP = CI.getPreprocessor();
PP.addPPCallbacks(std::move(MacroCallback));
- // Invoke as normal
- WrapperFrontendAction::ExecuteAction();
+ // If we are targeting a root signature, invoke custom handling
+ if (IsRootSignatureTarget)
+ return hlsl::HandleRootSignatureTarget(S, HLSLEntry);
+ else // otherwise, invoke as normal
+ return WrapperFrontendAction::ExecuteAction();
}
HLSLFrontendAction::HLSLFrontendAction(
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 1af72f8b1c934..91976489ee660 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -7,8 +7,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/ParseHLSLRootSignature.h"
-
+#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/LiteralSupport.h"
+#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
using namespace llvm::hlsl::rootsig;
@@ -1472,5 +1473,38 @@ IdentifierInfo *ParseHLSLRootSignature(Sema &Actions,
return DeclIdent;
}
+void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) {
+ ASTConsumer *Consumer = &S.getASTConsumer();
+
+ // Minimally initalize the parser. This does a couple things:
+ // - initializes Sema scope handling
+ // - invokes HLSLExternalSemaSource
+ // - invokes the preprocessor to lex the macros in the file
+ std::unique_ptr<Parser> P(new Parser(S.getPreprocessor(), S, true));
+ S.getPreprocessor().EnterMainSourceFile();
+
+ bool HaveLexer = S.getPreprocessor().getCurrentLexer();
+ if (HaveLexer) {
+ P->Initialize();
+ S.ActOnStartOfTranslationUnit();
+
+ // Skim through the file to parse to find the define
+ while (P->getCurToken().getKind() != tok::eof)
+ P->ConsumeAnyToken();
+
+ HLSLRootSignatureDecl *SignatureDecl =
+ S.HLSL().lookupRootSignatureOverrideDecl(
+ S.getASTContext().getTranslationUnitDecl());
+
+ if (SignatureDecl)
+ Consumer->HandleTopLevelDecl(DeclGroupRef(SignatureDecl));
+ else
+ S.getDiagnostics().Report(diag::err_hlsl_rootsignature_entry)
+ << EntryRootSig;
+ }
+
+ Consumer->HandleTranslationUnit(S.getASTContext());
+}
+
} // namespace hlsl
} // namespace clang
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index e0b936db7a9cb..c14ce2a2b84f8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -729,19 +729,15 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
// If we have specified a root signature to override the entry function then
// attach it now
- if (RootSigOverrideIdent) {
- LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
- Sema::LookupOrdinaryName);
- if (SemaRef.LookupQualifiedName(R, FD->getDeclContext()))
- if (auto *SignatureDecl =
- dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
- FD->dropAttr<RootSignatureAttr>();
- // We could look up the SourceRange of the macro here as well
- AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(),
- SourceRange(), ParsedAttr::Form::Microsoft());
- FD->addAttr(::new (getASTContext()) RootSignatureAttr(
- getASTContext(), AL, RootSigOverrideIdent, SignatureDecl));
- }
+ HLSLRootSignatureDecl *SignatureDecl =
+ lookupRootSignatureOverrideDecl(FD->getDeclContext());
+ if (SignatureDecl) {
+ FD->dropAttr<RootSignatureAttr>();
+ // We could look up the SourceRange of the macro here as well
+ AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(),
+ SourceRange(), ParsedAttr::Form::Microsoft());
+ FD->addAttr(::new (getASTContext()) RootSignatureAttr(
+ getASTContext(), AL, RootSigOverrideIdent, SignatureDecl));
}
llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
@@ -765,6 +761,8 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
case llvm::Triple::UnknownEnvironment:
case llvm::Triple::Library:
break;
+ case llvm::Triple::RootSignature:
+ llvm_unreachable("rootsig environment has no functions");
default:
llvm_unreachable("Unhandled environment in triple");
}
@@ -847,6 +845,8 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
}
}
break;
+ case llvm::Triple::RootSignature:
+ llvm_unreachable("rootsig environment has no function entry point");
default:
llvm_unreachable("Unhandled environment in triple");
}
@@ -1123,6 +1123,18 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
}
+HLSLRootSignatureDecl *
+SemaHLSL::lookupRootSignatureOverrideDecl(DeclContext *DC) const {
+ if (RootSigOverrideIdent) {
+ LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (SemaRef.LookupQualifiedName(R, DC))
+ return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl());
+ }
+
+ return nullptr;
+}
+
namespace {
struct PerVisibilityBindingChecker {
diff --git a/clang/test/AST/HLSL/RootSignature-Target-AST.hlsl b/clang/test/AST/HLSL/RootSignature-Target-AST.hlsl
new file mode 100644
index 0000000000000..91441e32e047d
--- /dev/null
+++ b/clang/test/AST/HLSL/RootSignature-Target-AST.hlsl
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -ast-dump \
+// RUN: -hlsl-entry EntryRootSig -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-V1_1
+
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -ast-dump \
+// RUN: -fdx-rootsignature-version=rootsig_1_0 \
+// RUN: -hlsl-entry EntryRootSig -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-V1_0
+
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -ast-dump \
+// RUN: -D CmdRS='"UAV(u0)"'\
+// RUN: -hlsl-entry CmdRS -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CMD
+
+// CHECK: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[ENTRY_RS_DECL:__hlsl_rootsig_decl_\d*]]
+// CHECK-V1_0-SAME: version: 1.0,
+// CHECK-V1_1-SAME: version: 1.1,
+// CHECK-SAME: RootElements{
+// CHECK-SAME: RootCBV(b0,
+// CHECK-SAME: space = 0, visibility = All,
+// CHECK-V1_0-SAME: flags = DataVolatile
+// CHECK-V1_1-SAME: flags = DataStaticWhileSetAtExecute
+// CHECK-SAME: )
+// CHECK-SAME: }
+#define EntryRootSig "CBV(b0)"
+
+// CMD: -HLSLRootSignatureDecl 0x{{.*}} {{.*}} implicit [[CMD_RS_DECL:__hlsl_rootsig_decl_\d*]]
+// CMD-SAME: version: 1.1,
+// CMD-SAME: RootElements{
+// CMD-SAME: RootUAV(u0, space = 0, visibility = All, flags = DataVolatile)
+// CMD-SAME: }
diff --git a/clang/test/CodeGenHLSL/RootSignature-Target.hlsl b/clang/test/CodeGenHLSL/RootSignature-Target.hlsl
new file mode 100644
index 0000000000000..50e6bae6786f0
--- /dev/null
+++ b/clang/test/CodeGenHLSL/RootSignature-Target.hlsl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-rootsignature \
+// RUN: -hlsl-entry EntryRS -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: !dx.rootsignatures = !{![[#ENTRY:]]}
+// CHECK: ![[#ENTRY]] = !{null, ![[#ENTRY_RS:]], i32 2}
+// CHECK: ![[#ENTRY_RS]] = !{![[#ROOT_CBV:]]}
+// CHECK: ![[#ROOT_CBV]] = !{!"RootCBV", i32 0, i32 0, i32 0, i32 4}
+
+#define EntryRS "CBV(b0)"
diff --git a/clang/test/Driver/dxc_rootsignature_target.hlsl b/clang/test/Driver/dxc_rootsignature_target.hlsl
new file mode 100644
index 0000000000000..08cd1ab00089b
--- /dev/null
+++ b/clang/test/Driver/dxc_rootsignature_target.hlsl
@@ -0,0 +1,8 @@
+// RUN: %clang_dxc -E EntryRS -T rootsig_1_1 /Fo %t.dxo -### %s 2>&1 | FileCheck %s --check-prefix=CMDS
+
+// CMDS: "{{.*}}clang{{.*}}" "-cc1"
+// CMDS-SAME: "-triple" "dxilv1.1-unknown-shadermodel1.1-rootsignature"
+// CMDS-SAME: "-hlsl-entry" "EntryRS"
+// CMDS: "{{.*}}llvm-objcopy{{(.exe)?}}" "{{.*}}.dxo" "--only-section=RTS0"
+
+#define EntryRS "UAV(u0)"
diff --git a/clang/test/SemaHLSL/RootSignature-target-err.hlsl b/clang/test/SemaHLSL/RootSignature-target-err.hlsl
new file mode 100644
index 0000000000000..49aca9ed6b377
--- /dev/null
+++ b/clang/test/SemaHLSL/RootSignature-target-err.hlsl
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-rootsignature -hlsl-entry NotFoundRS -fsyntax-only %s -verify
+
+// expected-error@* {{rootsignature specified as target environment but entry, NotFoundRS, was not defined}}
+
+#define EntryRootSig "CBV(b0)"
diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index f74c9775cb3f3..0547d96a8dec7 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -45,7 +45,7 @@ namespace dxbc {
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
inline Triple::EnvironmentType getShaderStage(uint32_t Kind) {
- assert(Kind <= Triple::Amplification - Triple::Pixel &&
+ assert(Kind <= Triple::RootSignature - Triple::Pixel &&
"Shader kind out of expected range.");
return static_cast<Triple::EnvironmentType>(Triple::Pixel + Kind);
}
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 8e12c6852075d..c8fa482a9a4f4 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -305,6 +305,7 @@ class Triple {
Callable,
Mesh,
Amplification,
+ RootSignature,
OpenCL,
OpenHOS,
Mlibc,
@@ -872,7 +873,7 @@ class Triple {
Env == Triple::Intersection || Env == Triple::AnyHit ||
Env == Triple::ClosestHit || Env == Triple::Miss ||
Env == Triple::Callable || Env == Triple::Mesh ||
- Env == Triple::Amplification;
+ Env == Triple::Amplification || Env == Triple::RootSignature;
}
/// Tests whether the target is SPIR (32- or 64-bit).
diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
index a1ef2578f00aa..ca81d30473c03 100644
--- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
@@ -158,12 +158,15 @@ void DXContainerGlobals::addRootSignature(Module &M,
if (MMI.ShaderProfile == llvm::Triple::Library)
return;
- assert(MMI.EntryPropertyVec.size() == 1);
-
auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
- const Function *EntryFunction = MMI.EntryPropertyVec[0].Entry;
- const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction);
+ const Function *EntryFunction = nullptr;
+ if (MMI.ShaderProfile != llvm::Triple::RootSignature) {
+ assert(MMI.EntryPropertyVec.size() == 1);
+ EntryFunction = MMI.EntryPropertyVec[0].Entry;
+ }
+
+ const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction);
if (!RS)
return;
@@ -258,7 +261,8 @@ void DXContainerGlobals::addPipelineStateValidationInfo(
dxil::ModuleMetadataInfo &MMI =
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
assert(MMI.EntryPropertyVec.size() == 1 ||
- MMI.ShaderProfile == Triple::Library);
+ MMI.ShaderProfile == Triple::Library ||
+ MMI.ShaderProfile == Triple::RootSignature);
PSV.BaseData.ShaderStage =
static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel);
@@ -279,7 +283,8 @@ void DXContainerGlobals::addPipelineStateValidationInfo(
break;
}
- if (MMI.ShaderProfile != Triple::Library)
+ if (MMI.ShaderProfile != Triple::Library &&
+ MMI.ShaderProfile != Triple::RootSignature)
PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName();
PSV.finalize(MMI.ShaderProfile);
diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp
index 2436d3869464f..9cfc47d187c5f 100644
--- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp
+++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp
@@ -72,6 +72,13 @@ analyzeModule(Module &M) {
if (RootSignatureNode == nullptr)
return RSDMap;
+ bool AllowNullFunctions = false;
+ if (M.getTargetTriple().getEnvironment() ==
+ Triple::EnvironmentType::RootSignature) {
+ assert(RootSignatureNode->getNumOperands() == 1);
+ AllowNullFunctions = true;
+ }
+
for (const auto &RSDefNode : RootSignatureNode->operands()) {
if (RSDefNode->getNumOperands() != 3) {
reportError(Ctx, "Invalid Root Signature metadata - expected function, "
@@ -80,24 +87,28 @@ analyzeModule(Module &M) {
}
// Function was pruned during compilation.
- const MDOperand &FunctionPointerMdNode = RSDefNode->getOperand(0);
- if (FunctionPointerMdNode == nullptr) {
- reportError(
- Ctx, "Function associated with Root Signature definition is null.");
- continue;
- }
+ Function *F = nullptr;
+
+ if (!AllowNullFunctions) {
+ const MDOperand &FunctionPointerMdNode = RSDefNode->getOperand(0);
+ if (FunctionPointerMdNode == nullptr) {
+ reportError(
+ Ctx, "Function associated with Root Signature definition is null.");
+ continue;
+ }
- ValueAsMetadata *VAM =
- llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get());
- if (VAM == nullptr) {
- reportError(Ctx, "First element of root signature is not a Value");
- continue;
- }
+ ValueAsMetadata *VAM =
+ llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get());
+ if (VAM == nullptr) {
+ reportError(Ctx, "First element of root signature is not a Value");
+ continue;
+ }
- Function *F = dyn_cast<Function>(VAM->getValue());
- if (F == nullptr) {
- reportError(Ctx, "First element of root signature is not a Function");
- continue;
+ F = dyn_cast<Function>(VAM->getValue());
+ if (F == nullptr) {
+ reportError(Ctx, "First element of root signature is not a Function");
+ continue;
+ }
}
Metadata *RootElementListOperand = RSDefNode->getOperand(1).get();
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 82bcacee7a6dd..9eebcc9b13063 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -127,6 +127,8 @@ static StringRef getShortShaderStage(Triple::EnvironmentType Env) {
return "ms";
case Triple::Amplification:
return "as";
+ case Triple::RootSignature:
+ return "rootsig";
default:
break;
}
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index 71517e5e9e832..ac3626db46ea9 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -391,6 +391,8 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) {
case Callable: return "callable";
case Mesh: return "mesh";
case Amplification: return "amplification";
+ case RootSignature:
+ return "rootsignature";
case OpenCL:
return "opencl";
case OpenHOS: return "ohos";
@@ -787,6 +789,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) {
.StartsWith("callable", Triple::Callable)
.StartsWith("mesh", Triple::Mesh)
.StartsWith("amplification", Triple::Amplification)
+ .StartsWith("rootsignature", Triple::RootSignature)
.StartsWith("opencl", Triple::OpenCL)
.StartsWith("ohos", Triple::OpenHOS)
.StartsWith("pauthtest", Triple::PAuthTest)
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll
new file mode 100644
index 0000000000000..76212a0f66f9d
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Target.ll
@@ -0,0 +1,23 @@
+; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s
+; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+
+target triple = "dxil-unknown-shadermodel1.1-rootsignature"
+
+; CHECK: @dx.rts0 = private constant [24 x i8] c"{{.*}}", section "RTS0", align 4
+
+!dx.rootsignatures = !{!2} ; list of function/root signature pairs
+!2 = !{ null, !3, i32 2 } ; function, root signature, version
+!3 = !{ !4 } ; list of root signature elements
+!4 = !{ !"RootFlags", i32 1 } ; 1 = allow_input_assembler_input_layout
+
+; DXC: - Name: RTS0
+; DXC-NEXT: Size: 24
+; DXC-NEXT: RootSignature:
+; DXC-NEXT: Version: 2
+; DXC-NEXT: NumRootParameters: 0
+; DXC-NEXT: RootParametersOffset: 24
+; DXC-NEXT: NumStaticSamplers: 0
+; DXC-NEXT: StaticSamplersOffset: 24
+; DXC-NEXT: Parameters: []
+; DXC-NEXT: AllowInputAssemblerInputLayout: true
+
diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp
index d2ca30583fe82..e6979cf49ce82 100644
--- a/llvm/unittests/TargetParser/TripleTest.cpp
+++ b/llvm/unittests/TargetParser/TripleTest.cpp
@@ -546,6 +546,22 @@ TEST(TripleTest, ParsedIDs) {
EXPECT_EQ(VersionTuple(1, 8), T.getDXILVersion());
EXPECT_EQ(Triple::Amplification, T.getEnvironment());
+ T = Triple("dxilv1.0-unknown-shadermodel1.0-rootsignature");
+ EXPECT_EQ(Triple::dxil, T.getArch());
+ EXPECT_EQ(Triple::DXILSubArch_v1_0, T.getSubArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::ShaderModel, T.getOS());
+ EXPECT_EQ(VersionTuple(1, 0), T.getDXILVersion());
+ EXPECT_EQ(Triple::RootSignature, T.getEnvironment());
+
+ T = Triple("dxilv1.1-unknown-shadermodel1.1-rootsignature");
+ EXPECT_EQ(Triple::dxil, T.getArch());
+ EXPECT_EQ(Triple::DXILSubArch_v1_1, T.getSubArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::ShaderModel, T.getOS());
+ EXPECT_EQ(VersionTuple(1, 1), T.getDXILVersion());
+ EXPECT_EQ(Triple::RootSignature, T.getEnvironment());
+
T = Triple("dxilv1.8-unknown-shadermodel6.15-library");
EXPECT_EQ(Triple::dxil, T.getArch());
EXPECT_EQ(Triple::DXILSubArch_v1_8, T.getSubArch());
More information about the llvm-commits
mailing list