1 //===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "CommonArgs.h"
11 #include "clang/Driver/Compilation.h"
12 #include "clang/Driver/DriverDiagnostic.h"
13 #include "clang/Driver/Job.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/TargetParser/Triple.h"
17 using namespace clang::driver
;
18 using namespace clang::driver::tools
;
19 using namespace clang::driver::toolchains
;
20 using namespace clang
;
21 using namespace llvm::opt
;
26 const unsigned OfflineLibMinor
= 0xF;
28 bool isLegalShaderModel(Triple
&T
) {
29 if (T
.getOS() != Triple::OSType::ShaderModel
)
32 auto Version
= T
.getOSVersion();
33 if (Version
.getBuild())
35 if (Version
.getSubminor())
38 auto Kind
= T
.getEnvironment();
43 case Triple::EnvironmentType::Vertex
:
44 case Triple::EnvironmentType::Hull
:
45 case Triple::EnvironmentType::Domain
:
46 case Triple::EnvironmentType::Geometry
:
47 case Triple::EnvironmentType::Pixel
:
48 case Triple::EnvironmentType::Compute
: {
49 VersionTuple
MinVer(4, 0);
50 return MinVer
<= Version
;
52 case Triple::EnvironmentType::Library
: {
53 VersionTuple
SM6x(6, OfflineLibMinor
);
57 VersionTuple
MinVer(6, 3);
58 return MinVer
<= Version
;
60 case Triple::EnvironmentType::Amplification
:
61 case Triple::EnvironmentType::Mesh
: {
62 VersionTuple
MinVer(6, 5);
63 return MinVer
<= Version
;
69 std::optional
<std::string
> tryParseProfile(StringRef Profile
) {
70 // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
71 SmallVector
<StringRef
, 3> Parts
;
72 Profile
.split(Parts
, "_");
73 if (Parts
.size() != 3)
76 Triple::EnvironmentType Kind
=
77 StringSwitch
<Triple::EnvironmentType
>(Parts
[0])
78 .Case("ps", Triple::EnvironmentType::Pixel
)
79 .Case("vs", Triple::EnvironmentType::Vertex
)
80 .Case("gs", Triple::EnvironmentType::Geometry
)
81 .Case("hs", Triple::EnvironmentType::Hull
)
82 .Case("ds", Triple::EnvironmentType::Domain
)
83 .Case("cs", Triple::EnvironmentType::Compute
)
84 .Case("lib", Triple::EnvironmentType::Library
)
85 .Case("ms", Triple::EnvironmentType::Mesh
)
86 .Case("as", Triple::EnvironmentType::Amplification
)
87 .Default(Triple::EnvironmentType::UnknownEnvironment
);
88 if (Kind
== Triple::EnvironmentType::UnknownEnvironment
)
91 unsigned long long Major
= 0;
92 if (llvm::getAsUnsignedInteger(Parts
[1], 0, Major
))
95 unsigned long long Minor
= 0;
96 if (Parts
[2] == "x" && Kind
== Triple::EnvironmentType::Library
)
97 Minor
= OfflineLibMinor
;
98 else if (llvm::getAsUnsignedInteger(Parts
[2], 0, Minor
))
101 // dxil-unknown-shadermodel-hull
103 T
.setArch(Triple::ArchType::dxil
);
104 T
.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel
).str() +
105 VersionTuple(Major
, Minor
).getAsString());
106 T
.setEnvironment(Kind
);
107 if (isLegalShaderModel(T
))
108 return T
.getTriple();
113 bool isLegalValidatorVersion(StringRef ValVersionStr
, const Driver
&D
) {
114 VersionTuple Version
;
115 if (Version
.tryParse(ValVersionStr
) || Version
.getBuild() ||
116 Version
.getSubminor() || !Version
.getMinor()) {
117 D
.Diag(diag::err_drv_invalid_format_dxil_validator_version
)
122 uint64_t Major
= Version
.getMajor();
123 uint64_t Minor
= *Version
.getMinor();
124 if (Major
== 0 && Minor
!= 0) {
125 D
.Diag(diag::err_drv_invalid_empty_dxil_validator_version
) << ValVersionStr
;
128 VersionTuple
MinVer(1, 0);
129 if (Version
< MinVer
) {
130 D
.Diag(diag::err_drv_invalid_range_dxil_validator_version
) << ValVersionStr
;
138 void tools::hlsl::Validator::ConstructJob(Compilation
&C
, const JobAction
&JA
,
139 const InputInfo
&Output
,
140 const InputInfoList
&Inputs
,
142 const char *LinkingOutput
) const {
143 std::string DxvPath
= getToolChain().GetProgramPath("dxv");
144 assert(DxvPath
!= "dxv" && "cannot find dxv");
146 ArgStringList CmdArgs
;
147 assert(Inputs
.size() == 1 && "Unable to handle multiple inputs.");
148 const InputInfo
&Input
= Inputs
[0];
149 assert(Input
.isFilename() && "Unexpected verify input");
150 // Grabbing the output of the earlier cc1 run.
151 CmdArgs
.push_back(Input
.getFilename());
152 // Use the same name as output.
153 CmdArgs
.push_back("-o");
154 CmdArgs
.push_back(Input
.getFilename());
156 const char *Exec
= Args
.MakeArgString(DxvPath
);
157 C
.addCommand(std::make_unique
<Command
>(JA
, *this, ResponseFileSupport::None(),
158 Exec
, CmdArgs
, Inputs
, Input
));
161 /// DirectX Toolchain
162 HLSLToolChain::HLSLToolChain(const Driver
&D
, const llvm::Triple
&Triple
,
164 : ToolChain(D
, Triple
, Args
) {
165 if (Args
.hasArg(options::OPT_dxc_validator_path_EQ
))
166 getProgramPaths().push_back(
167 Args
.getLastArgValue(options::OPT_dxc_validator_path_EQ
).str());
170 Tool
*clang::driver::toolchains::HLSLToolChain::getTool(
171 Action::ActionClass AC
) const {
173 case Action::BinaryAnalyzeJobClass
:
175 Validator
.reset(new tools::hlsl::Validator(*this));
176 return Validator
.get();
178 return ToolChain::getTool(AC
);
182 std::optional
<std::string
>
183 clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
184 StringRef TargetProfile
) {
185 return tryParseProfile(TargetProfile
);
189 HLSLToolChain::TranslateArgs(const DerivedArgList
&Args
, StringRef BoundArch
,
190 Action::OffloadKind DeviceOffloadKind
) const {
191 DerivedArgList
*DAL
= new DerivedArgList(Args
.getBaseArgs());
193 const OptTable
&Opts
= getDriver().getOpts();
195 for (Arg
*A
: Args
) {
196 if (A
->getOption().getID() == options::OPT_dxil_validator_version
) {
197 StringRef ValVerStr
= A
->getValue();
198 std::string ErrorMsg
;
199 if (!isLegalValidatorVersion(ValVerStr
, getDriver()))
202 if (A
->getOption().getID() == options::OPT_dxc_entrypoint
) {
203 DAL
->AddSeparateArg(nullptr, Opts
.getOption(options::OPT_hlsl_entrypoint
),
208 if (A
->getOption().getID() == options::OPT__SLASH_O
) {
209 StringRef OStr
= A
->getValue();
211 DAL
->AddFlagArg(nullptr, Opts
.getOption(options::OPT_O0
));
215 DAL
->AddJoinedArg(nullptr, Opts
.getOption(options::OPT_O
), OStr
);
220 if (A
->getOption().getID() == options::OPT_emit_pristine_llvm
) {
221 // Translate fcgl into -S -emit-llvm and -disable-llvm-passes.
222 DAL
->AddFlagArg(nullptr, Opts
.getOption(options::OPT_S
));
223 DAL
->AddFlagArg(nullptr, Opts
.getOption(options::OPT_emit_llvm
));
224 DAL
->AddFlagArg(nullptr,
225 Opts
.getOption(options::OPT_disable_llvm_passes
));
232 // Add default validator version if not set.
233 // TODO: remove this once read validator version from validator.
234 if (!DAL
->hasArg(options::OPT_dxil_validator_version
)) {
235 const StringRef DefaultValidatorVer
= "1.7";
236 DAL
->AddSeparateArg(nullptr,
237 Opts
.getOption(options::OPT_dxil_validator_version
),
238 DefaultValidatorVer
);
240 if (!DAL
->hasArg(options::OPT_O_Group
)) {
241 DAL
->AddJoinedArg(nullptr, Opts
.getOption(options::OPT_O
), "3");
243 // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and
245 // See: https://github.com/llvm/llvm-project/issues/57876
249 bool HLSLToolChain::requiresValidation(DerivedArgList
&Args
) const {
250 if (Args
.getLastArg(options::OPT_dxc_disable_validation
))
253 std::string DxvPath
= GetProgramPath("dxv");
254 if (DxvPath
!= "dxv")
257 getDriver().Diag(diag::warn_drv_dxc_missing_dxv
);