Skip to content

Commit 74a4d81

Browse files
authored
[HLSL][DirectX] Add the Qdx-rootsignature-strip driver option (#154454)
This pr adds the `Qstrip-rootsignature` as a `DXC` driver option. To do so, this pr introduces the `BinaryModifyJobClass` as an `Action` to modify a produced object file before its final output. Further, it registers `llvm-objcopy` as the tool to modify a produced `DXContainer` on the `HLSL` toolchain. This allows us to specify the `Qstrip-rootsignature` option to `clang-dxc` which will invoke `llvm-objcopy` with a `--remove-section=RTS0` argument to implement its functionality. Resolves: #150275.
1 parent f09986a commit 74a4d81

File tree

8 files changed

+126
-15
lines changed

8 files changed

+126
-15
lines changed

clang/include/clang/Driver/Action.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ class Action {
7676
StaticLibJobClass,
7777
BinaryAnalyzeJobClass,
7878
BinaryTranslatorJobClass,
79+
ObjcopyJobClass,
7980

8081
JobClassFirst = PreprocessJobClass,
81-
JobClassLast = BinaryTranslatorJobClass
82+
JobClassLast = ObjcopyJobClass
8283
};
8384

8485
// The offloading kind determines if this action is binded to a particular
@@ -687,6 +688,17 @@ class BinaryTranslatorJobAction : public JobAction {
687688
}
688689
};
689690

691+
class ObjcopyJobAction : public JobAction {
692+
void anchor() override;
693+
694+
public:
695+
ObjcopyJobAction(Action *Input, types::ID Type);
696+
697+
static bool classof(const Action *A) {
698+
return A->getKind() == ObjcopyJobClass;
699+
}
700+
};
701+
690702
} // namespace driver
691703
} // namespace clang
692704

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9404,6 +9404,11 @@ def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
94049404
Visibility<[DXCOption, ClangOption, CC1Option]>,
94059405
HelpText<"Assume that UAVs/SRVs may alias">,
94069406
MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>;
9407+
def dxc_strip_rootsignature :
9408+
Option<["/", "-"], "Qstrip-rootsignature", KIND_FLAG>,
9409+
Group<dxc_Group>,
9410+
Visibility<[DXCOption]>,
9411+
HelpText<"Omit the root signature from produced DXContainer">;
94079412
def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
94089413
HelpText<"Set target profile">,
94099414
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,"

clang/lib/Driver/Action.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ const char *Action::getClassName(ActionClass AC) {
5252
return "binary-analyzer";
5353
case BinaryTranslatorJobClass:
5454
return "binary-translator";
55+
case ObjcopyJobClass:
56+
return "objcopy";
5557
}
5658

5759
llvm_unreachable("invalid class");
@@ -467,3 +469,8 @@ void BinaryTranslatorJobAction::anchor() {}
467469
BinaryTranslatorJobAction::BinaryTranslatorJobAction(Action *Input,
468470
types::ID Type)
469471
: JobAction(BinaryTranslatorJobClass, Input, Type) {}
472+
473+
void ObjcopyJobAction::anchor() {}
474+
475+
ObjcopyJobAction::ObjcopyJobAction(Action *Input, types::ID Type)
476+
: JobAction(ObjcopyJobClass, Input, Type) {}

clang/lib/Driver/Driver.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4642,16 +4642,28 @@ void Driver::BuildDefaultActions(Compilation &C, DerivedArgList &Args,
46424642
}
46434643
}
46444644

4645-
// Call validator for dxil when -Vd not in Args.
46464645
if (C.getDefaultToolChain().getTriple().isDXIL()) {
4647-
// Only add action when needValidation.
46484646
const auto &TC =
46494647
static_cast<const toolchains::HLSLToolChain &>(C.getDefaultToolChain());
4648+
4649+
// Call objcopy for manipulation of the unvalidated DXContainer when an
4650+
// option in Args requires it.
4651+
if (TC.requiresObjcopy(Args)) {
4652+
Action *LastAction = Actions.back();
4653+
// llvm-objcopy expects an unvalidated DXIL container (TY_OBJECT).
4654+
if (LastAction->getType() == types::TY_Object)
4655+
Actions.push_back(
4656+
C.MakeAction<ObjcopyJobAction>(LastAction, types::TY_Object));
4657+
}
4658+
4659+
// Call validator for dxil when -Vd not in Args.
46504660
if (TC.requiresValidation(Args)) {
46514661
Action *LastAction = Actions.back();
46524662
Actions.push_back(C.MakeAction<BinaryAnalyzeJobAction>(
46534663
LastAction, types::TY_DX_CONTAINER));
46544664
}
4665+
4666+
// Call metal-shaderconverter when targeting metal.
46554667
if (TC.requiresBinaryTranslation(Args)) {
46564668
Action *LastAction = Actions.back();
46574669
// Metal shader converter runs on DXIL containers, which can either be
@@ -6253,8 +6265,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
62536265
C.getArgs().hasArg(options::OPT_dxc_Fo)) ||
62546266
JA.getType() == types::TY_DX_CONTAINER) {
62556267
StringRef FoValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fo);
6256-
// If we are targeting DXIL and not validating or translating, we should set
6257-
// the final result file. Otherwise we should emit to a temporary.
6268+
// If we are targeting DXIL and not validating/translating/objcopying, we
6269+
// should set the final result file. Otherwise we should emit to a
6270+
// temporary.
62586271
if (C.getDefaultToolChain().getTriple().isDXIL()) {
62596272
const auto &TC = static_cast<const toolchains::HLSLToolChain &>(
62606273
C.getDefaultToolChain());

clang/lib/Driver/ToolChain.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
652652
case Action::VerifyDebugInfoJobClass:
653653
case Action::BinaryAnalyzeJobClass:
654654
case Action::BinaryTranslatorJobClass:
655+
case Action::ObjcopyJobClass:
655656
llvm_unreachable("Invalid tool kind.");
656657

657658
case Action::CompileJobClass:

clang/lib/Driver/ToolChains/HLSL.cpp

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,32 @@ void tools::hlsl::MetalConverter::ConstructJob(
294294
Exec, CmdArgs, Inputs, Input));
295295
}
296296

297+
void tools::hlsl::LLVMObjcopy::ConstructJob(Compilation &C, const JobAction &JA,
298+
const InputInfo &Output,
299+
const InputInfoList &Inputs,
300+
const ArgList &Args,
301+
const char *LinkingOutput) const {
302+
303+
std::string ObjcopyPath = getToolChain().GetProgramPath("llvm-objcopy");
304+
const char *Exec = Args.MakeArgString(ObjcopyPath);
305+
306+
ArgStringList CmdArgs;
307+
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
308+
const InputInfo &Input = Inputs[0];
309+
CmdArgs.push_back(Input.getFilename());
310+
CmdArgs.push_back(Output.getFilename());
311+
312+
if (Args.hasArg(options::OPT_dxc_strip_rootsignature)) {
313+
const char *Frs = Args.MakeArgString("--remove-section=RTS0");
314+
CmdArgs.push_back(Frs);
315+
}
316+
317+
assert(CmdArgs.size() > 2 && "Unnecessary invocation of objcopy.");
318+
319+
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
320+
Exec, CmdArgs, Inputs, Input));
321+
}
322+
297323
/// DirectX Toolchain
298324
HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
299325
const ArgList &Args)
@@ -314,6 +340,10 @@ Tool *clang::driver::toolchains::HLSLToolChain::getTool(
314340
if (!MetalConverter)
315341
MetalConverter.reset(new tools::hlsl::MetalConverter(*this));
316342
return MetalConverter.get();
343+
case Action::ObjcopyJobClass:
344+
if (!LLVMObjcopy)
345+
LLVMObjcopy.reset(new tools::hlsl::LLVMObjcopy(*this));
346+
return LLVMObjcopy.get();
317347
default:
318348
return ToolChain::getTool(AC);
319349
}
@@ -458,16 +488,22 @@ bool HLSLToolChain::requiresBinaryTranslation(DerivedArgList &Args) const {
458488
return Args.hasArg(options::OPT_metal) && Args.hasArg(options::OPT_dxc_Fo);
459489
}
460490

491+
bool HLSLToolChain::requiresObjcopy(DerivedArgList &Args) const {
492+
return Args.hasArg(options::OPT_dxc_Fo) &&
493+
Args.hasArg(options::OPT_dxc_strip_rootsignature);
494+
}
495+
461496
bool HLSLToolChain::isLastJob(DerivedArgList &Args,
462497
Action::ActionClass AC) const {
463-
bool HasTranslation = requiresBinaryTranslation(Args);
464-
bool HasValidation = requiresValidation(Args);
465-
// If translation and validation are not required, we should only have one
466-
// action.
467-
if (!HasTranslation && !HasValidation)
468-
return true;
469-
if ((HasTranslation && AC == Action::BinaryTranslatorJobClass) ||
470-
(!HasTranslation && HasValidation && AC == Action::BinaryAnalyzeJobClass))
471-
return true;
472-
return false;
498+
// Note: we check in the reverse order of execution
499+
if (requiresBinaryTranslation(Args))
500+
return AC == Action::Action::BinaryTranslatorJobClass;
501+
if (requiresValidation(Args))
502+
return AC == Action::Action::BinaryAnalyzeJobClass;
503+
if (requiresObjcopy(Args))
504+
return AC == Action::Action::ObjcopyJobClass;
505+
506+
// No translation, validation, or objcopy are required, so this action must
507+
// output to the result file.
508+
return true;
473509
}

clang/lib/Driver/ToolChains/HLSL.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ class LLVM_LIBRARY_VISIBILITY MetalConverter : public Tool {
4242
const llvm::opt::ArgList &TCArgs,
4343
const char *LinkingOutput) const override;
4444
};
45+
46+
class LLVM_LIBRARY_VISIBILITY LLVMObjcopy : public Tool {
47+
public:
48+
LLVMObjcopy(const ToolChain &TC)
49+
: Tool("hlsl::LLVMObjcopy", "llvm-objcopy", TC) {}
50+
51+
bool hasIntegratedCPP() const override { return false; }
52+
53+
void ConstructJob(Compilation &C, const JobAction &JA,
54+
const InputInfo &Output, const InputInfoList &Inputs,
55+
const llvm::opt::ArgList &TCArgs,
56+
const char *LinkingOutput) const override;
57+
};
58+
4559
} // namespace hlsl
4660
} // namespace tools
4761

@@ -65,6 +79,13 @@ class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain {
6579
static std::optional<std::string> parseTargetProfile(StringRef TargetProfile);
6680
bool requiresValidation(llvm::opt::DerivedArgList &Args) const;
6781
bool requiresBinaryTranslation(llvm::opt::DerivedArgList &Args) const;
82+
bool requiresObjcopy(llvm::opt::DerivedArgList &Args) const;
83+
84+
/// If we are targeting DXIL then the last job should output the DXContainer
85+
/// to the specified output file with /Fo. Otherwise, we will emit to a
86+
/// temporary file for the next job to use.
87+
///
88+
/// Returns true if we should output to the final result file.
6889
bool isLastJob(llvm::opt::DerivedArgList &Args, Action::ActionClass AC) const;
6990

7091
// Set default DWARF version to 4 for DXIL uses version 4.
@@ -73,6 +94,7 @@ class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain {
7394
private:
7495
mutable std::unique_ptr<tools::hlsl::Validator> Validator;
7596
mutable std::unique_ptr<tools::hlsl::MetalConverter> MetalConverter;
97+
mutable std::unique_ptr<tools::hlsl::LLVMObjcopy> LLVMObjcopy;
7698
};
7799

78100
} // end namespace toolchains
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Create a dummy dxv to run
2+
// RUN: mkdir -p %t.dir
3+
// RUN: echo "dxv" > %t.dir/dxv && chmod 754 %t.dir/dxv
4+
5+
// RUN: %clang_dxc -Qstrip-rootsignature --dxv-path=%t.dir -T cs_6_0 /Fo %t.dxo -### %s 2>&1 | FileCheck %s
6+
7+
// Test to demonstrate that we specify to the root signature with the
8+
// -Qstrip-rootsignature option and that it occurs before DXV
9+
10+
// CHECK: "{{.*}}llvm-objcopy{{(.exe)?}}" "{{.*}}.obj" "{{.*}}.obj" "--remove-section=RTS0"
11+
// CHECK: "{{.*}}dxv{{(.exe)?}}" "{{.*}}.obj" "-o" "{{.*}}.dxo"
12+
13+
[shader("compute"), RootSignature("")]
14+
[numthreads(1,1,1)]
15+
void EmptyEntry() {}

0 commit comments

Comments
 (0)