Coverage Report

Created: 2023-09-12 09:32

/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
}