New option --dxv-path is added for dxc mode to set the installation path for dxv.
If cannot find dxv, a warning will be report.
dxv will be executed with command line dxv file_name -o file_name.
It will validate and sign the file and overwrite it.
Differential Revision: https://reviews.llvm.org/D141705
"target profile option (-T) is missing">;
def err_drv_hlsl_unsupported_target : Error<
"HLSL code generation is unsupported for target '%0'">;
+def warn_drv_dxc_missing_dxv : Warning<"dxv not found. "
+ "Resulting DXIL will not be validated or signed for use in release environments.">,
+ InGroup<DXILValidation>;
def err_drv_invalid_range_dxil_validator_version : Error<
"invalid validator version : %0\n"
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;
+// Warnings for DXIL validation
+def DXILValidation : DiagGroup<"dxil-validation">;
+
// Warnings and notes related to const_var_decl_type attribute checks
def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;
OffloadPackagerJobClass,
LinkerWrapperJobClass,
StaticLibJobClass,
+ BinaryAnalyzeJobClass,
JobClassFirst = PreprocessJobClass,
- JobClassLast = StaticLibJobClass
+ JobClassLast = BinaryAnalyzeJobClass
};
// The offloading kind determines if this action is binded to a particular
}
};
+class BinaryAnalyzeJobAction : public JobAction {
+ void anchor() override;
+
+public:
+ BinaryAnalyzeJobAction(Action *Input, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == BinaryAnalyzeJobClass;
+ }
+};
+
} // namespace driver
} // namespace clang
Group<dxc_Group>,
Flags<[DXCOption, NoXarchOption]>,
HelpText<"Entry point name">;
+def dxc_validator_path_EQ : Joined<["--"], "dxv-path=">, Group<dxc_Group>,
+ HelpText<"DXIL validator installation path">;
+def dxc_disable_validation : DXCFlag<"Vd">,
+ HelpText<"Disable validation">;
TYPE("cuda-fatbin", CUDA_FATBIN, INVALID, "fatbin", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("hip-fatbin", HIP_FATBIN, INVALID, "hipfb", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("api-information", API_INFO, INVALID, "json", phases::Precompile)
+TYPE("dx-container", DX_CONTAINER, INVALID, "dxo", phases::Compile, phases::Backend)
TYPE("none", Nothing, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
return "clang-linker-wrapper";
case StaticLibJobClass:
return "static-lib-linker";
+ case BinaryAnalyzeJobClass:
+ return "binary-analyzer";
}
llvm_unreachable("invalid class");
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
: JobAction(StaticLibJobClass, Inputs, Type) {}
+
+void BinaryAnalyzeJobAction::anchor() {}
+
+BinaryAnalyzeJobAction::BinaryAnalyzeJobAction(Action *Input, types::ID Type)
+ : JobAction(BinaryAnalyzeJobClass, Input, Type) {}
I.second->claim();
}
+ // Call validator for dxil when -Vd not in Args.
+ if (C.getDefaultToolChain().getTriple().isDXIL()) {
+ // Only add action when needValidation.
+ const auto &TC =
+ static_cast<const toolchains::HLSLToolChain &>(C.getDefaultToolChain());
+ if (TC.requiresValidation(Args)) {
+ Action *LastAction = Actions.back();
+ Actions.push_back(C.MakeAction<BinaryAnalyzeJobAction>(
+ LastAction, types::TY_DX_CONTAINER));
+ }
+ }
+
// Claim ignored clang-cl options.
Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
}
unsigned NumIfsOutputs = 0;
for (const Action *A : C.getActions()) {
if (A->getType() != types::TY_Nothing &&
+ A->getType() != types::TY_DX_CONTAINER &&
!(A->getKind() == Action::IfsMergeJobClass ||
(A->getType() == clang::driver::types::TY_IFS_CPP &&
A->getKind() == clang::driver::Action::CompileJobClass &&
case Action::LipoJobClass:
case Action::DsymutilJobClass:
case Action::VerifyDebugInfoJobClass:
+ case Action::BinaryAnalyzeJobClass:
llvm_unreachable("Invalid tool kind.");
case Action::CompileJobClass:
#include "HLSL.h"
#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Job.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
} // namespace
+void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ std::string DxvPath = getToolChain().GetProgramPath("dxv");
+ assert(DxvPath != "dxv" && "cannot find dxv");
+
+ ArgStringList CmdArgs;
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Unexpected verify input");
+ // Grabbing the output of the earlier cc1 run.
+ CmdArgs.push_back(Input.getFilename());
+ // Use the same name as output.
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec = Args.MakeArgString(DxvPath);
+ 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)
- : ToolChain(D, Triple, Args) {}
+ : ToolChain(D, Triple, Args) {
+ if (Args.hasArg(options::OPT_dxc_validator_path_EQ))
+ getProgramPaths().push_back(
+ Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str());
+}
+
+Tool *clang::driver::toolchains::HLSLToolChain::getTool(
+ Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::BinaryAnalyzeJobClass:
+ if (!Validator)
+ Validator.reset(new tools::hlsl::Validator(*this));
+ return Validator.get();
+ default:
+ return ToolChain::getTool(AC);
+ }
+}
std::optional<std::string>
clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
// See: https://github.com/llvm/llvm-project/issues/57876
return DAL;
}
+
+bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const {
+ if (Args.getLastArg(options::OPT_dxc_disable_validation))
+ return false;
+
+ std::string DxvPath = GetProgramPath("dxv");
+ if (DxvPath != "dxv")
+ return true;
+
+ getDriver().Diag(diag::warn_drv_dxc_missing_dxv);
+ return false;
+}
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H
+#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
namespace clang {
namespace driver {
+namespace tools {
+
+namespace hlsl {
+class LLVM_LIBRARY_VISIBILITY Validator : public Tool {
+public:
+ Validator(const ToolChain &TC) : Tool("hlsl::Validator", "dxv", 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
+
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain {
public:
HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
+ Tool *getTool(Action::ActionClass AC) const override;
+
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
static std::optional<std::string> parseTargetProfile(StringRef TargetProfile);
+ bool requiresValidation(llvm::opt::DerivedArgList &Args) const;
+
+private:
+ mutable std::unique_ptr<tools::hlsl::Validator> Validator;
};
} // end namespace toolchains
-// RUN: %clang_dxc -DTEST=2 -### %s 2>&1 | FileCheck %s
+// RUN: %clang_dxc -DTEST=2 -Tlib_6_7 -### %s 2>&1 | FileCheck %s
// RUN: %clang_dxc -DTEST=2 -Tlib_6_7 %s -fcgl -Fo - | FileCheck %s --check-prefix=ERROR
// Make sure -D send to cc1.
-// RUN: %clang_dxc -I test -### %s 2>&1 | FileCheck %s
+// RUN: %clang_dxc -I test -Tlib_6_3 -### %s 2>&1 | FileCheck %s
// Make sure -I send to cc1.
// CHECK:"-I" "test"
--- /dev/null
+// RUN: %clang_dxc -I test -Tlib_6_3 -### %s 2>&1 | FileCheck %s
+
+// Make sure report warning.
+// CHECK:dxv not found.
+
+// RUN: echo "dxv" > %T/dxv && chmod 754 %T/dxv && %clang_dxc --dxv-path=%T %s -Tlib_6_3 -### 2>&1 | FileCheck %s --check-prefix=DXV_PATH
+// DXV_PATH:dxv{{(.exe)?}}" "-" "-o" "-"
+
+// RUN: %clang_dxc -I test -Vd -Tlib_6_3 -### %s 2>&1 | FileCheck %s --check-prefix=VD
+// VD:"-cc1"{{.*}}"-triple" "dxil-unknown-shadermodel6.3-library"
+// VD-NOT:dxv not found
+
+// RUN: %clang_dxc -Tlib_6_3 -ccc-print-bindings --dxv-path=%T -Fo %t.dxo %s 2>&1 | FileCheck %s --check-prefix=BINDINGS
+// BINDINGS: "dxil-unknown-shadermodel6.3-library" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[DXC:.+]].dxo"
+// BINDINGS-NEXT: "dxil-unknown-shadermodel6.3-library" - "hlsl::Validator", inputs: ["[[DXC]].dxo"], output: "[[DXC]].dxo"
+
+// RUN: %clang_dxc -Tlib_6_3 -ccc-print-phases --dxv-path=%T -Fo %t.dxc %s 2>&1 | FileCheck %s --check-prefix=PHASES
+
+// PHASES: 0: input, "[[INPUT:.+]]", hlsl
+// PHASES-NEXT: 1: preprocessor, {0}, c++-cpp-output
+// PHASES-NEXT: 2: compiler, {1}, ir
+// PHASES-NEXT: 3: backend, {2}, assembler
+// PHASES-NEXT: 4: binary-analyzer, {3}, dx-container
DiagnosticsEngine &Diags) {
Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
std::unique_ptr<Compilation> C{TheDriver.BuildCompilation(
- {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"})};
+ {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl", "-Vd"})};
EXPECT_TRUE(C);
EXPECT_STREQ(TheDriver.getTargetTriple().c_str(), ExpectTriple.data());
EXPECT_EQ(Diags.getNumErrors(), 0u);
unsigned NumOfErrors) {
Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
std::unique_ptr<Compilation> C{TheDriver.BuildCompilation(
- {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"})};
+ {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl", "-Vd"})};
EXPECT_TRUE(C);
EXPECT_EQ(Diags.getNumErrors(), NumOfErrors);
EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), ExpectError.data());