clang 20.0.0git
HLSL.cpp
Go to the documentation of this file.
1//===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "HLSL.h"
10#include "CommonArgs.h"
13#include "clang/Driver/Job.h"
14#include "llvm/ADT/StringSwitch.h"
15#include "llvm/TargetParser/Triple.h"
16
17using namespace clang::driver;
18using namespace clang::driver::tools;
19using namespace clang::driver::toolchains;
20using namespace clang;
21using namespace llvm::opt;
22using namespace llvm;
23
24namespace {
25
26const unsigned OfflineLibMinor = 0xF;
27
28bool isLegalShaderModel(Triple &T) {
29 if (T.getOS() != Triple::OSType::ShaderModel)
30 return false;
31
32 auto Version = T.getOSVersion();
33 if (Version.getBuild())
34 return false;
35 if (Version.getSubminor())
36 return false;
37
38 auto Kind = T.getEnvironment();
39
40 switch (Kind) {
41 default:
42 return false;
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;
51 } break;
52 case Triple::EnvironmentType::Library: {
53 VersionTuple SM6x(6, OfflineLibMinor);
54 if (Version == SM6x)
55 return true;
56
57 VersionTuple MinVer(6, 3);
58 return MinVer <= Version;
59 } break;
60 case Triple::EnvironmentType::Amplification:
61 case Triple::EnvironmentType::Mesh: {
62 VersionTuple MinVer(6, 5);
63 return MinVer <= Version;
64 } break;
65 }
66 return false;
67}
68
69std::optional<std::string> tryParseProfile(StringRef Profile) {
70 // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
72 Profile.split(Parts, "_");
73 if (Parts.size() != 3)
74 return std::nullopt;
75
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)
89 return std::nullopt;
90
91 unsigned long long Major = 0;
92 if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
93 return std::nullopt;
94
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))
99 return std::nullopt;
100
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
105 llvm::Triple T;
106 Triple::SubArchType SubArch = llvm::Triple::NoSubArch;
107 switch (Minor) {
108 case 0:
109 SubArch = llvm::Triple::DXILSubArch_v1_0;
110 break;
111 case 1:
112 SubArch = llvm::Triple::DXILSubArch_v1_1;
113 break;
114 case 2:
115 SubArch = llvm::Triple::DXILSubArch_v1_2;
116 break;
117 case 3:
118 SubArch = llvm::Triple::DXILSubArch_v1_3;
119 break;
120 case 4:
121 SubArch = llvm::Triple::DXILSubArch_v1_4;
122 break;
123 case 5:
124 SubArch = llvm::Triple::DXILSubArch_v1_5;
125 break;
126 case 6:
127 SubArch = llvm::Triple::DXILSubArch_v1_6;
128 break;
129 case 7:
130 SubArch = llvm::Triple::DXILSubArch_v1_7;
131 break;
132 case 8:
133 SubArch = llvm::Triple::DXILSubArch_v1_8;
134 break;
135 case OfflineLibMinor:
136 // Always consider minor version x as the latest supported DXIL version
137 SubArch = llvm::Triple::LatestDXILSubArch;
138 break;
139 default:
140 // No DXIL Version corresponding to specified Shader Model version found
141 return std::nullopt;
142 }
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();
149 else
150 return std::nullopt;
151}
152
153bool 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)
158 << ValVersionStr;
159 return false;
160 }
161
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;
166 return false;
167 }
168 VersionTuple MinVer(1, 0);
169 if (Version < MinVer) {
170 D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr;
171 return false;
172 }
173 return true;
174}
175
176} // namespace
177
179 const InputInfo &Output,
180 const InputInfoList &Inputs,
181 const ArgList &Args,
182 const char *LinkingOutput) const {
183 std::string DxvPath = getToolChain().GetProgramPath("dxv");
184 assert(DxvPath != "dxv" && "cannot find dxv");
185
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());
195
196 const char *Exec = Args.MakeArgString(DxvPath);
197 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
198 Exec, CmdArgs, Inputs, Input));
199}
200
201/// DirectX Toolchain
202HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
203 const ArgList &Args)
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());
208}
209
211 Action::ActionClass AC) const {
212 switch (AC) {
214 if (!Validator)
215 Validator.reset(new tools::hlsl::Validator(*this));
216 return Validator.get();
217 default:
218 return ToolChain::getTool(AC);
219 }
220}
221
222std::optional<std::string>
224 StringRef TargetProfile) {
225 return tryParseProfile(TargetProfile);
226}
227
228DerivedArgList *
229HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
230 Action::OffloadKind DeviceOffloadKind) const {
231 DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
232
233 const OptTable &Opts = getDriver().getOpts();
234
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()))
240 continue;
241 }
242 if (A->getOption().getID() == options::OPT_dxc_entrypoint) {
243 DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint),
244 A->getValue());
245 A->claim();
246 continue;
247 }
248 if (A->getOption().getID() == options::OPT__SLASH_O) {
249 StringRef OStr = A->getValue();
250 if (OStr == "d") {
251 DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0));
252 A->claim();
253 continue;
254 } else {
255 DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr);
256 A->claim();
257 continue;
258 }
259 }
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));
265 A->claim();
266 continue;
267 }
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) {
274 DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_std_EQ),
275 l.getName());
276 } else {
277 getDriver().Diag(diag::err_drv_invalid_value) << "HV" << A->getValue();
278 }
279
280 A->claim();
281 continue;
282 }
283 DAL->append(A);
284 }
285
286 if (!DAL->hasArg(options::OPT_O_Group)) {
287 DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3");
288 }
289
290 return DAL;
291}
292
293bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const {
294 if (Args.getLastArg(options::OPT_dxc_disable_validation))
295 return false;
296
297 std::string DxvPath = GetProgramPath("dxv");
298 if (DxvPath != "dxv")
299 return true;
300
301 getDriver().Diag(diag::warn_drv_dxc_missing_dxv);
302 return false;
303}
const Decl * D
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:144
const llvm::opt::OptTable & getOpts() const
Definition: Driver.h:399
InputInfo - Wrapper for information about an input source.
Definition: InputInfo.h:22
const char * getFilename() const
Definition: InputInfo.h:83
bool isFilename() const
Definition: InputInfo.h:75
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:92
const Driver & getDriver() const
Definition: ToolChain.h:252
path_list & getProgramPaths()
Definition: ToolChain.h:297
std::string GetProgramPath(const char *Name) const
Definition: ToolChain.cpp:903
virtual Tool * getTool(Action::ActionClass AC) const
Definition: ToolChain.cpp:561
Tool - Information on a specific compilation tool.
Definition: Tool.h:32
const ToolChain & getToolChain() const
Definition: Tool.h:52
Tool * getTool(Action::ActionClass AC) const override
Definition: HLSL.cpp:210
HLSLToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
DirectX Toolchain.
Definition: HLSL.cpp:202
llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override
TranslateArgs - Create a new derived argument list for any argument translations this ToolChain may w...
Definition: HLSL.cpp:229
bool requiresValidation(llvm::opt::DerivedArgList &Args) const
Definition: HLSL.cpp:293
static std::optional< std::string > parseTargetProfile(StringRef TargetProfile)
Definition: HLSL.cpp:223
void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override
ConstructJob - Construct jobs to perform the action JA, writing to Output and with Inputs,...
Definition: HLSL.cpp:178
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
llvm::StringRef getAsString(SyncScope S)
Definition: SyncScope.h:60
unsigned long uint64_t
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
LangStandard - Information about the properties of a particular language standard.
Definition: LangStandard.h:72
static Kind getHLSLLangKind(StringRef Name)
static const LangStandard & getLangStandardForKind(Kind K)
const char * getName() const
getName - Get the name of this standard.
Definition: LangStandard.h:87
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.
Definition: Job.h:78