-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[HLSL][DirectX] Add the Qdx-rootsignature-strip driver option #154454
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-hlsl @llvm/pr-subscribers-clang-driver Author: Finn Plummer (inbelic) ChangesIt pr adds the To do so, this pr introduces the Further, it registers This allows us to specify the Resolves: #150275. Full diff: https://github.com/llvm/llvm-project/pull/154454.diff 9 Files Affected:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 423b696785500..89e9f5b5853bb 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -479,6 +479,9 @@ CODEGENOPT(StaticClosure, 1, 0, Benign)
/// Assume that UAVs/SRVs may alias
CODEGENOPT(ResMayAlias, 1, 0, Benign)
+/// Omit the root signature from produced DXContainer
+CODEGENOPT(HLSLRootSigStrip, 1, 0, Benign)
+
/// Controls how unwind v2 (epilog) information should be generated for x64
/// Windows.
ENUM_CODEGENOPT(WinX64EHUnwindV2, WinX64EHUnwindV2Mode,
diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h
index 7aecfd886adb8..6fc515f9e4049 100644
--- a/clang/include/clang/Driver/Action.h
+++ b/clang/include/clang/Driver/Action.h
@@ -76,9 +76,10 @@ class Action {
StaticLibJobClass,
BinaryAnalyzeJobClass,
BinaryTranslatorJobClass,
+ BinaryModifyJobClass,
JobClassFirst = PreprocessJobClass,
- JobClassLast = BinaryTranslatorJobClass
+ JobClassLast = BinaryModifyJobClass
};
// The offloading kind determines if this action is binded to a particular
@@ -687,6 +688,17 @@ class BinaryTranslatorJobAction : public JobAction {
}
};
+class BinaryModifyJobAction : public JobAction {
+ void anchor() override;
+
+public:
+ BinaryModifyJobAction(Action *Input, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == BinaryModifyJobClass;
+ }
+};
+
} // namespace driver
} // namespace clang
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6aab43c9ed57f..1bd3f09ae1df1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -9381,6 +9381,12 @@ def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
Visibility<[DXCOption, ClangOption, CC1Option]>,
HelpText<"Assume that UAVs/SRVs may alias">,
MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>;
+def dxc_strip_rootsignature :
+ Option<["/", "-"], "Qstrip-rootsignature", KIND_FLAG>,
+ Group<dxc_Group>,
+ Visibility<[DXCOption]>,
+ HelpText<"Omit the root signature from produced DXContainer">,
+ MarshallingInfoFlag<CodeGenOpts<"HLSLRootSigStrip">>;
def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
HelpText<"Set target profile">,
Values<"ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7,"
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp
index ec09726044812..fbf80b3c6f124 100644
--- a/clang/lib/Driver/Action.cpp
+++ b/clang/lib/Driver/Action.cpp
@@ -52,6 +52,8 @@ const char *Action::getClassName(ActionClass AC) {
return "binary-analyzer";
case BinaryTranslatorJobClass:
return "binary-translator";
+ case BinaryModifyJobClass:
+ return "binary-modifier";
}
llvm_unreachable("invalid class");
@@ -467,3 +469,8 @@ void BinaryTranslatorJobAction::anchor() {}
BinaryTranslatorJobAction::BinaryTranslatorJobAction(Action *Input,
types::ID Type)
: JobAction(BinaryTranslatorJobClass, Input, Type) {}
+
+void BinaryModifyJobAction::anchor() {}
+
+BinaryModifyJobAction::BinaryModifyJobAction(Action *Input, types::ID Type)
+ : JobAction(BinaryModifyJobClass, Input, Type) {}
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 586f287843f3e..59a4eadcd5d85 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -4601,6 +4601,16 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Actions.push_back(C.MakeAction<BinaryTranslatorJobAction>(
LastAction, types::TY_DX_CONTAINER));
}
+ if (TC.requiresObjcopy(Args)) {
+ Action *LastAction = Actions.back();
+ // llvm-objcopy expects a DXIL container, which can either be
+ // validated (in which case they are TY_DX_CONTAINER), or unvalidated
+ // (TY_OBJECT).
+ if (LastAction->getType() == types::TY_DX_CONTAINER ||
+ LastAction->getType() == types::TY_Object)
+ Actions.push_back(C.MakeAction<BinaryModifyJobAction>(
+ LastAction, types::TY_DX_CONTAINER));
+ }
}
// Claim ignored clang-cl options.
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 25c6b5a486fd5..713bda1d7244d 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -652,6 +652,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::VerifyDebugInfoJobClass:
case Action::BinaryAnalyzeJobClass:
case Action::BinaryTranslatorJobClass:
+ case Action::BinaryModifyJobClass:
llvm_unreachable("Invalid tool kind.");
case Action::CompileJobClass:
diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp
index 38f4643abad98..a554c15f1e7c6 100644
--- a/clang/lib/Driver/ToolChains/HLSL.cpp
+++ b/clang/lib/Driver/ToolChains/HLSL.cpp
@@ -247,6 +247,30 @@ void tools::hlsl::MetalConverter::ConstructJob(
Exec, CmdArgs, Inputs, Input));
}
+void tools::hlsl::LLVMObjcopy::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ std::string ObjcopyPath = getToolChain().GetProgramPath("llvm-objcopy");
+ const char *Exec = Args.MakeArgString(ObjcopyPath);
+
+ ArgStringList CmdArgs;
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ const InputInfo &Input = Inputs[0];
+ CmdArgs.push_back(Input.getFilename());
+ CmdArgs.push_back(Output.getFilename());
+
+ if (Args.hasArg(options::OPT_dxc_strip_rootsignature)) {
+ const char *Frs = Args.MakeArgString("--remove-section=RTS0");
+ CmdArgs.push_back(Frs);
+ }
+
+ C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+ Exec, CmdArgs, Inputs, Input));
+}
+
/// DirectX Toolchain
HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
@@ -267,6 +291,10 @@ Tool *clang::driver::toolchains::HLSLToolChain::getTool(
if (!MetalConverter)
MetalConverter.reset(new tools::hlsl::MetalConverter(*this));
return MetalConverter.get();
+ case Action::BinaryModifyJobClass:
+ if (!LLVMObjcopy)
+ LLVMObjcopy.reset(new tools::hlsl::LLVMObjcopy(*this));
+ return LLVMObjcopy.get();
default:
return ToolChain::getTool(AC);
}
@@ -404,16 +432,25 @@ bool HLSLToolChain::requiresBinaryTranslation(DerivedArgList &Args) const {
return Args.hasArg(options::OPT_metal) && Args.hasArg(options::OPT_dxc_Fo);
}
+bool HLSLToolChain::requiresObjcopy(DerivedArgList &Args) const {
+ return Args.hasArg(options::OPT_dxc_Fo) &&
+ Args.hasArg(options::OPT_dxc_strip_rootsignature);
+}
+
bool HLSLToolChain::isLastJob(DerivedArgList &Args,
Action::ActionClass AC) const {
bool HasTranslation = requiresBinaryTranslation(Args);
bool HasValidation = requiresValidation(Args);
+ bool HasObjcopy = requiresObjcopy(Args);
// If translation and validation are not required, we should only have one
// action.
- if (!HasTranslation && !HasValidation)
+ if (!HasTranslation && !HasValidation && !HasObjcopy)
return true;
if ((HasTranslation && AC == Action::BinaryTranslatorJobClass) ||
- (!HasTranslation && HasValidation && AC == Action::BinaryAnalyzeJobClass))
+ (!HasTranslation && HasValidation &&
+ AC == Action::BinaryAnalyzeJobClass) ||
+ (!HasTranslation && !HasValidation && HasObjcopy &&
+ AC == Action::BinaryModifyJobClass))
return true;
return false;
}
diff --git a/clang/lib/Driver/ToolChains/HLSL.h b/clang/lib/Driver/ToolChains/HLSL.h
index 3824b4252324b..b81141b26b4e6 100644
--- a/clang/lib/Driver/ToolChains/HLSL.h
+++ b/clang/lib/Driver/ToolChains/HLSL.h
@@ -42,6 +42,19 @@ class LLVM_LIBRARY_VISIBILITY MetalConverter : public Tool {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
+
+class LLVM_LIBRARY_VISIBILITY LLVMObjcopy : public Tool {
+public:
+ LLVMObjcopy(const ToolChain &TC)
+ : Tool("hlsl::LLVMObjcopy", "llvm-objcopy", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
} // namespace hlsl
} // namespace tools
@@ -65,6 +78,7 @@ class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain {
static std::optional<std::string> parseTargetProfile(StringRef TargetProfile);
bool requiresValidation(llvm::opt::DerivedArgList &Args) const;
bool requiresBinaryTranslation(llvm::opt::DerivedArgList &Args) const;
+ bool requiresObjcopy(llvm::opt::DerivedArgList &Args) const;
bool isLastJob(llvm::opt::DerivedArgList &Args, Action::ActionClass AC) const;
// Set default DWARF version to 4 for DXIL uses version 4.
@@ -73,6 +87,7 @@ class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain {
private:
mutable std::unique_ptr<tools::hlsl::Validator> Validator;
mutable std::unique_ptr<tools::hlsl::MetalConverter> MetalConverter;
+ mutable std::unique_ptr<tools::hlsl::LLVMObjcopy> LLVMObjcopy;
};
} // end namespace toolchains
diff --git a/clang/test/Driver/dxc_strip_rootsignature.hlsl b/clang/test/Driver/dxc_strip_rootsignature.hlsl
new file mode 100644
index 0000000000000..b4af1f4b1541d
--- /dev/null
+++ b/clang/test/Driver/dxc_strip_rootsignature.hlsl
@@ -0,0 +1,22 @@
+// RUN: %clang_dxc -Qstrip-rootsignature -T cs_6_0 -HV 202x -Vd /Fo %t %s
+// RUN: obj2yaml %t | FileCheck %s
+// RUN: obj2yaml %t | FileCheck %s --check-prefix=OTHERS
+
+// Test to demonstrate that we specify to the root signature with the
+// -Qstrip-rootsignature option
+
+// CHECK-NOT: RTS0
+
+// OTHERS: FileSize: 1964
+// OTHERS-NEXT: PartCount: 6
+// OTHERS: Parts:
+// OTHERS: Name: DXIL
+// OTHERS: Name: SFI0
+// OTHERS: Name: HASH
+// OTHERS: Name: ISG1
+// OTHERS: Name: OSG1
+// OTHERS: Name: PSV0
+
+[shader("compute"), RootSignature("")]
+[numthreads(1,1,1)]
+void EmptyEntry() {}
|
clang/lib/Driver/Driver.cpp
Outdated
// llvm-objcopy expects a DXIL container, which can either be | ||
// validated (in which case they are TY_DX_CONTAINER), or unvalidated | ||
// (TY_OBJECT). | ||
if (LastAction->getType() == types::TY_DX_CONTAINER || |
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.
Should we be running this before validation rather than after? What does DXC do?
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.
Yep, DXC will construct the final output blob before running the validator. So it would validate with the parts removed.
644f3b1
to
4830024
Compare
- DXC will invoke the validator after the final blob has been generated (in this case after the part is removed)
4830024
to
154c2b0
Compare
clang/lib/Driver/Driver.cpp
Outdated
@@ -4647,6 +4647,16 @@ void Driver::BuildDefaultActions(Compilation &C, DerivedArgList &Args, | |||
// Only add action when needValidation. |
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.
The comments around the isDXIL block look like they're out of date or at least misplaced (both this one and the "Call validator" one above.
clang/lib/Driver/ToolChains/HLSL.h
Outdated
class LLVM_LIBRARY_VISIBILITY LLVMObjcopy : public Tool { | ||
public: | ||
LLVMObjcopy(const ToolChain &TC) : Tool("LLVMObjcopy", "llvm-objcopy", TC) {} | ||
|
||
bool hasIntegratedCPP() const override { return false; } | ||
|
||
void ConstructJob(Compilation &C, const JobAction &JA, | ||
const InputInfo &Output, const InputInfoList &Inputs, | ||
const llvm::opt::ArgList &TCArgs, | ||
const char *LinkingOutput) const override; | ||
}; |
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.
LLVMObjcopy
fairly generic, even if we are only using it in the HLSL toolchain right now. Should this class be defined somewhere less toolchain specific?
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.
While it is generic, the logic of ConstructJob
is specific to just the hlsl
toolchain.
It is convention for the other toolchains to each redefine their own version of the struct with their namespace prefixed. See Linker
etc.
So I have added back the hlsl
namespace to this struct.
Wait for Justin or Chris, this isn't my area of expertise. |
- following convention used from other toolchains (eg. `Linker`), each toolchain will need to define a custom override of `ConstructJob` so that it converts the applicable arguments accordingly - since this will be toolchain specific, it is convention to prefix it with the toolchain namespace (hlsl::)
clang/lib/Driver/ToolChains/HLSL.cpp
Outdated
if (!HasTranslation && !HasValidation) | ||
if (!HasTranslation && !HasValidation && !HasObjcopy) | ||
return true; | ||
if ((HasTranslation && AC == Action::BinaryTranslatorJobClass) || | ||
(!HasTranslation && HasValidation && AC == Action::BinaryAnalyzeJobClass)) | ||
(!HasTranslation && HasValidation && | ||
AC == Action::BinaryAnalyzeJobClass) || | ||
(!HasTranslation && !HasValidation && HasObjcopy && | ||
AC == Action::ObjcopyJobClass)) | ||
return true; | ||
return false; |
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.
This logic is getting a bit unweildy. Would it simplify things to work from the last job backwards? That is,
if (HasObjcopy)
return AC == Action::ObjcopyJobClass;
if (HasValidation)
return AC == Action::BinaryAnalyzeJobClass;
if (HasTranslation)
return AC == Action::BinaryTranslatorJobClass;
// If none of translation, validation, or objcopy are required, we should only
// have one action
return true;
/// Omit the root signature from produced DXContainer | ||
CODEGENOPT(HLSLRootSigStrip, 1, 0, Benign) |
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.
Do we need this anymore? I don't see it being used, and I would think that making this a separate tool's job would make this unnecessary.
6bdf65e
to
7dd6205
Compare
This pr adds the
Qstrip-rootsignature
as aDXC
driver option.To do so, this pr introduces the
BinaryModifyJobClass
as anAction
to modify a produced object file before its final output.Further, it registers
llvm-objcopy
as the tool to modify a producedDXContainer
on theHLSL
toolchain.This allows us to specify the
Qstrip-rootsignature
option toclang-dxc
which will invokellvm-objcopy
with a--remove-section=RTS0
argument to implement its functionality.Resolves: #150275.