/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp
Line | Count | Source (jump to first uncovered line) |
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" |
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" |
16 | | |
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; |
22 | | using namespace llvm; |
23 | | |
24 | | namespace { |
25 | | |
26 | | const unsigned OfflineLibMinor = 0xF; |
27 | | |
28 | 59 | bool isLegalShaderModel(Triple &T) { |
29 | 59 | if (T.getOS() != Triple::OSType::ShaderModel) |
30 | 0 | return false; |
31 | | |
32 | 59 | auto Version = T.getOSVersion(); |
33 | 59 | if (Version.getBuild()) |
34 | 0 | return false; |
35 | 59 | if (Version.getSubminor()) |
36 | 0 | return false; |
37 | | |
38 | 59 | auto Kind = T.getEnvironment(); |
39 | | |
40 | 59 | switch (Kind) { |
41 | 0 | default: |
42 | 0 | return false; |
43 | 1 | case Triple::EnvironmentType::Vertex: |
44 | 2 | case Triple::EnvironmentType::Hull: |
45 | 4 | case Triple::EnvironmentType::Domain: |
46 | 5 | case Triple::EnvironmentType::Geometry: |
47 | 6 | case Triple::EnvironmentType::Pixel: |
48 | 9 | case Triple::EnvironmentType::Compute: { |
49 | 9 | VersionTuple MinVer(4, 0); |
50 | 9 | return MinVer <= Version; |
51 | 6 | } break0 ; |
52 | 48 | case Triple::EnvironmentType::Library: { |
53 | 48 | VersionTuple SM6x(6, OfflineLibMinor); |
54 | 48 | if (Version == SM6x) |
55 | 1 | return true; |
56 | | |
57 | 47 | VersionTuple MinVer(6, 3); |
58 | 47 | return MinVer <= Version; |
59 | 48 | } break0 ; |
60 | 1 | case Triple::EnvironmentType::Amplification: |
61 | 2 | case Triple::EnvironmentType::Mesh: { |
62 | 2 | VersionTuple MinVer(6, 5); |
63 | 2 | return MinVer <= Version; |
64 | 1 | } break0 ; |
65 | 59 | } |
66 | 0 | return false; |
67 | 59 | } |
68 | | |
69 | 62 | std::optional<std::string> tryParseProfile(StringRef Profile) { |
70 | | // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] |
71 | 62 | SmallVector<StringRef, 3> Parts; |
72 | 62 | Profile.split(Parts, "_"); |
73 | 62 | if (Parts.size() != 3) |
74 | 1 | return std::nullopt; |
75 | | |
76 | 61 | Triple::EnvironmentType Kind = |
77 | 61 | StringSwitch<Triple::EnvironmentType>(Parts[0]) |
78 | 61 | .Case("ps", Triple::EnvironmentType::Pixel) |
79 | 61 | .Case("vs", Triple::EnvironmentType::Vertex) |
80 | 61 | .Case("gs", Triple::EnvironmentType::Geometry) |
81 | 61 | .Case("hs", Triple::EnvironmentType::Hull) |
82 | 61 | .Case("ds", Triple::EnvironmentType::Domain) |
83 | 61 | .Case("cs", Triple::EnvironmentType::Compute) |
84 | 61 | .Case("lib", Triple::EnvironmentType::Library) |
85 | 61 | .Case("ms", Triple::EnvironmentType::Mesh) |
86 | 61 | .Case("as", Triple::EnvironmentType::Amplification) |
87 | 61 | .Default(Triple::EnvironmentType::UnknownEnvironment); |
88 | 61 | if (Kind == Triple::EnvironmentType::UnknownEnvironment) |
89 | 1 | return std::nullopt; |
90 | | |
91 | 60 | unsigned long long Major = 0; |
92 | 60 | if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) |
93 | 0 | return std::nullopt; |
94 | | |
95 | 60 | unsigned long long Minor = 0; |
96 | 60 | if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library2 ) |
97 | 1 | Minor = OfflineLibMinor; |
98 | 59 | else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) |
99 | 1 | return std::nullopt; |
100 | | |
101 | | // dxil-unknown-shadermodel-hull |
102 | 59 | llvm::Triple T; |
103 | 59 | T.setArch(Triple::ArchType::dxil); |
104 | 59 | T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + |
105 | 59 | VersionTuple(Major, Minor).getAsString()); |
106 | 59 | T.setEnvironment(Kind); |
107 | 59 | if (isLegalShaderModel(T)) |
108 | 58 | return T.getTriple(); |
109 | 1 | else |
110 | 1 | return std::nullopt; |
111 | 59 | } |
112 | | |
113 | 5 | bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { |
114 | 5 | VersionTuple Version; |
115 | 5 | if (Version.tryParse(ValVersionStr) || Version.getBuild()3 || |
116 | 5 | Version.getSubminor()3 || !Version.getMinor()3 ) { |
117 | 3 | D.Diag(diag::err_drv_invalid_format_dxil_validator_version) |
118 | 3 | << ValVersionStr; |
119 | 3 | return false; |
120 | 3 | } |
121 | | |
122 | 2 | uint64_t Major = Version.getMajor(); |
123 | 2 | uint64_t Minor = *Version.getMinor(); |
124 | 2 | if (Major == 0 && Minor != 01 ) { |
125 | 1 | D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; |
126 | 1 | return false; |
127 | 1 | } |
128 | 1 | VersionTuple MinVer(1, 0); |
129 | 1 | if (Version < MinVer) { |
130 | 0 | D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; |
131 | 0 | return false; |
132 | 0 | } |
133 | 1 | return true; |
134 | 1 | } |
135 | | |
136 | | } // namespace |
137 | | |
138 | | void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA, |
139 | | const InputInfo &Output, |
140 | | const InputInfoList &Inputs, |
141 | | const ArgList &Args, |
142 | 1 | const char *LinkingOutput) const { |
143 | 1 | std::string DxvPath = getToolChain().GetProgramPath("dxv"); |
144 | 1 | assert(DxvPath != "dxv" && "cannot find dxv"); |
145 | | |
146 | 1 | ArgStringList CmdArgs; |
147 | 1 | assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); |
148 | 1 | const InputInfo &Input = Inputs[0]; |
149 | 1 | assert(Input.isFilename() && "Unexpected verify input"); |
150 | | // Grabbing the output of the earlier cc1 run. |
151 | 1 | CmdArgs.push_back(Input.getFilename()); |
152 | | // Use the same name as output. |
153 | 1 | CmdArgs.push_back("-o"); |
154 | 1 | CmdArgs.push_back(Input.getFilename()); |
155 | | |
156 | 1 | const char *Exec = Args.MakeArgString(DxvPath); |
157 | 1 | C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), |
158 | 1 | Exec, CmdArgs, Inputs, Input)); |
159 | 1 | } |
160 | | |
161 | | /// DirectX Toolchain |
162 | | HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, |
163 | | const ArgList &Args) |
164 | 68 | : ToolChain(D, Triple, Args) { |
165 | 68 | if (Args.hasArg(options::OPT_dxc_validator_path_EQ)) |
166 | 3 | getProgramPaths().push_back( |
167 | 3 | Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str()); |
168 | 68 | } |
169 | | |
170 | | Tool *clang::driver::toolchains::HLSLToolChain::getTool( |
171 | 2 | Action::ActionClass AC) const { |
172 | 2 | switch (AC) { |
173 | 2 | case Action::BinaryAnalyzeJobClass: |
174 | 2 | if (!Validator) |
175 | 2 | Validator.reset(new tools::hlsl::Validator(*this)); |
176 | 2 | return Validator.get(); |
177 | 0 | default: |
178 | 0 | return ToolChain::getTool(AC); |
179 | 2 | } |
180 | 2 | } |
181 | | |
182 | | std::optional<std::string> |
183 | | clang::driver::toolchains::HLSLToolChain::parseTargetProfile( |
184 | 62 | StringRef TargetProfile) { |
185 | 62 | return tryParseProfile(TargetProfile); |
186 | 62 | } |
187 | | |
188 | | DerivedArgList * |
189 | | HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, |
190 | 67 | Action::OffloadKind DeviceOffloadKind) const { |
191 | 67 | DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); |
192 | | |
193 | 67 | const OptTable &Opts = getDriver().getOpts(); |
194 | | |
195 | 444 | for (Arg *A : Args) { |
196 | 444 | if (A->getOption().getID() == options::OPT_dxil_validator_version) { |
197 | 5 | StringRef ValVerStr = A->getValue(); |
198 | 5 | std::string ErrorMsg; |
199 | 5 | if (!isLegalValidatorVersion(ValVerStr, getDriver())) |
200 | 4 | continue; |
201 | 5 | } |
202 | 440 | if (A->getOption().getID() == options::OPT_dxc_entrypoint) { |
203 | 2 | DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint), |
204 | 2 | A->getValue()); |
205 | 2 | A->claim(); |
206 | 2 | continue; |
207 | 2 | } |
208 | 438 | if (A->getOption().getID() == options::OPT__SLASH_O) { |
209 | 5 | StringRef OStr = A->getValue(); |
210 | 5 | if (OStr == "d") { |
211 | 1 | DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0)); |
212 | 1 | A->claim(); |
213 | 1 | continue; |
214 | 4 | } else { |
215 | 4 | DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr); |
216 | 4 | A->claim(); |
217 | 4 | continue; |
218 | 4 | } |
219 | 5 | } |
220 | 433 | if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { |
221 | | // Translate fcgl into -S -emit-llvm and -disable-llvm-passes. |
222 | 5 | DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); |
223 | 5 | DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); |
224 | 5 | DAL->AddFlagArg(nullptr, |
225 | 5 | Opts.getOption(options::OPT_disable_llvm_passes)); |
226 | 5 | A->claim(); |
227 | 5 | continue; |
228 | 5 | } |
229 | 428 | DAL->append(A); |
230 | 428 | } |
231 | | |
232 | | // Add default validator version if not set. |
233 | | // TODO: remove this once read validator version from validator. |
234 | 67 | if (!DAL->hasArg(options::OPT_dxil_validator_version)) { |
235 | 66 | const StringRef DefaultValidatorVer = "1.7"; |
236 | 66 | DAL->AddSeparateArg(nullptr, |
237 | 66 | Opts.getOption(options::OPT_dxil_validator_version), |
238 | 66 | DefaultValidatorVer); |
239 | 66 | } |
240 | 67 | if (!DAL->hasArg(options::OPT_O_Group)) { |
241 | 62 | DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); |
242 | 62 | } |
243 | | // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and |
244 | | // shader model 6.2. |
245 | | // See: https://github.com/llvm/llvm-project/issues/57876 |
246 | 67 | return DAL; |
247 | 67 | } |
248 | | |
249 | 68 | bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const { |
250 | 68 | if (Args.getLastArg(options::OPT_dxc_disable_validation)) |
251 | 23 | return false; |
252 | | |
253 | 45 | std::string DxvPath = GetProgramPath("dxv"); |
254 | 45 | if (DxvPath != "dxv") |
255 | 3 | return true; |
256 | | |
257 | 42 | getDriver().Diag(diag::warn_drv_dxc_missing_dxv); |
258 | 42 | return false; |
259 | 45 | } |