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 // Determine DXIL version using the minor version number of Shader
102 // Model version specified in target profile. Prior to decoupling DXIL version
103 // numbering from that of Shader Model DXIL version 1.Y corresponds to SM 6.Y.
104 // E.g., dxilv1.Y-unknown-shadermodelX.Y-hull
106 Triple::SubArchType SubArch
= llvm::Triple::NoSubArch
;
109 SubArch
= llvm::Triple::DXILSubArch_v1_0
;
112 SubArch
= llvm::Triple::DXILSubArch_v1_1
;
115 SubArch
= llvm::Triple::DXILSubArch_v1_2
;
118 SubArch
= llvm::Triple::DXILSubArch_v1_3
;
121 SubArch
= llvm::Triple::DXILSubArch_v1_4
;
124 SubArch
= llvm::Triple::DXILSubArch_v1_5
;
127 SubArch
= llvm::Triple::DXILSubArch_v1_6
;
130 SubArch
= llvm::Triple::DXILSubArch_v1_7
;
133 SubArch
= llvm::Triple::DXILSubArch_v1_8
;
135 case OfflineLibMinor
:
136 // Always consider minor version x as the latest supported DXIL version
137 SubArch
= llvm::Triple::LatestDXILSubArch
;
140 // No DXIL Version corresponding to specified Shader Model version found
143 T
.setArch(Triple::ArchType::dxil
, SubArch
);
144 T
.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel
).str() +
145 VersionTuple(Major
, Minor
).getAsString());
146 T
.setEnvironment(Kind
);
147 if (isLegalShaderModel(T
))
148 return T
.getTriple();
153 bool isLegalValidatorVersion(StringRef ValVersionStr
, const Driver
&D
) {
154 VersionTuple Version
;
155 if (Version
.tryParse(ValVersionStr
) || Version
.getBuild() ||
156 Version
.getSubminor() || !Version
.getMinor()) {
157 D
.Diag(diag::err_drv_invalid_format_dxil_validator_version
)
162 uint64_t Major
= Version
.getMajor();
163 uint64_t Minor
= *Version
.getMinor();
164 if (Major
== 0 && Minor
!= 0) {
165 D
.Diag(diag::err_drv_invalid_empty_dxil_validator_version
) << ValVersionStr
;
168 VersionTuple
MinVer(1, 0);
169 if (Version
< MinVer
) {
170 D
.Diag(diag::err_drv_invalid_range_dxil_validator_version
) << ValVersionStr
;
178 void tools::hlsl::Validator::ConstructJob(Compilation
&C
, const JobAction
&JA
,
179 const InputInfo
&Output
,
180 const InputInfoList
&Inputs
,
182 const char *LinkingOutput
) const {
183 std::string DxvPath
= getToolChain().GetProgramPath("dxv");
184 assert(DxvPath
!= "dxv" && "cannot find dxv");
186 ArgStringList CmdArgs
;
187 assert(Inputs
.size() == 1 && "Unable to handle multiple inputs.");
188 const InputInfo
&Input
= Inputs
[0];
189 assert(Input
.isFilename() && "Unexpected verify input");
190 // Grabbing the output of the earlier cc1 run.
191 CmdArgs
.push_back(Input
.getFilename());
192 // Use the same name as output.
193 CmdArgs
.push_back("-o");
194 CmdArgs
.push_back(Input
.getFilename());
196 const char *Exec
= Args
.MakeArgString(DxvPath
);
197 C
.addCommand(std::make_unique
<Command
>(JA
, *this, ResponseFileSupport::None(),
198 Exec
, CmdArgs
, Inputs
, Input
));
201 /// DirectX Toolchain
202 HLSLToolChain::HLSLToolChain(const Driver
&D
, const llvm::Triple
&Triple
,
204 : ToolChain(D
, Triple
, Args
) {
205 if (Args
.hasArg(options::OPT_dxc_validator_path_EQ
))
206 getProgramPaths().push_back(
207 Args
.getLastArgValue(options::OPT_dxc_validator_path_EQ
).str());
210 Tool
*clang::driver::toolchains::HLSLToolChain::getTool(
211 Action::ActionClass AC
) const {
213 case Action::BinaryAnalyzeJobClass
:
215 Validator
.reset(new tools::hlsl::Validator(*this));
216 return Validator
.get();
218 return ToolChain::getTool(AC
);
222 std::optional
<std::string
>
223 clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
224 StringRef TargetProfile
) {
225 return tryParseProfile(TargetProfile
);
229 HLSLToolChain::TranslateArgs(const DerivedArgList
&Args
, StringRef BoundArch
,
230 Action::OffloadKind DeviceOffloadKind
) const {
231 DerivedArgList
*DAL
= new DerivedArgList(Args
.getBaseArgs());
233 const OptTable
&Opts
= getDriver().getOpts();
235 for (Arg
*A
: Args
) {
236 if (A
->getOption().getID() == options::OPT_dxil_validator_version
) {
237 StringRef ValVerStr
= A
->getValue();
238 std::string ErrorMsg
;
239 if (!isLegalValidatorVersion(ValVerStr
, getDriver()))
242 if (A
->getOption().getID() == options::OPT_dxc_entrypoint
) {
243 DAL
->AddSeparateArg(nullptr, Opts
.getOption(options::OPT_hlsl_entrypoint
),
248 if (A
->getOption().getID() == options::OPT__SLASH_O
) {
249 StringRef OStr
= A
->getValue();
251 DAL
->AddFlagArg(nullptr, Opts
.getOption(options::OPT_O0
));
255 DAL
->AddJoinedArg(nullptr, Opts
.getOption(options::OPT_O
), OStr
);
260 if (A
->getOption().getID() == options::OPT_emit_pristine_llvm
) {
261 // Translate -fcgl into -emit-llvm and -disable-llvm-passes.
262 DAL
->AddFlagArg(nullptr, Opts
.getOption(options::OPT_emit_llvm
));
263 DAL
->AddFlagArg(nullptr,
264 Opts
.getOption(options::OPT_disable_llvm_passes
));
268 if (A
->getOption().getID() == options::OPT_dxc_hlsl_version
) {
269 // Translate -HV into -std for llvm
270 // depending on the value given
271 LangStandard::Kind LangStd
= LangStandard::getHLSLLangKind(A
->getValue());
272 if (LangStd
!= LangStandard::lang_unspecified
) {
273 LangStandard l
= LangStandard::getLangStandardForKind(LangStd
);
274 DAL
->AddSeparateArg(nullptr, Opts
.getOption(options::OPT_std_EQ
),
277 getDriver().Diag(diag::err_drv_invalid_value
) << "HV" << A
->getValue();
286 if (!DAL
->hasArg(options::OPT_O_Group
)) {
287 DAL
->AddJoinedArg(nullptr, Opts
.getOption(options::OPT_O
), "3");
293 bool HLSLToolChain::requiresValidation(DerivedArgList
&Args
) const {
294 if (Args
.getLastArg(options::OPT_dxc_disable_validation
))
297 std::string DxvPath
= GetProgramPath("dxv");
298 if (DxvPath
!= "dxv")
301 getDriver().Diag(diag::warn_drv_dxc_missing_dxv
);