Coverage Report

Created: 2020-02-15 09:57

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- HIP.cpp - HIP Tool and 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 "HIP.h"
10
#include "CommonArgs.h"
11
#include "InputInfo.h"
12
#include "clang/Basic/Cuda.h"
13
#include "clang/Driver/Compilation.h"
14
#include "clang/Driver/Driver.h"
15
#include "clang/Driver/DriverDiagnostic.h"
16
#include "clang/Driver/Options.h"
17
#include "llvm/Support/FileSystem.h"
18
#include "llvm/Support/Path.h"
19
20
using namespace clang::driver;
21
using namespace clang::driver::toolchains;
22
using namespace clang::driver::tools;
23
using namespace clang;
24
using namespace llvm::opt;
25
26
#if defined(_WIN32) || defined(_WIN64)
27
#define NULL_FILE "nul"
28
#else
29
30
#define NULL_FILE "/dev/null"
30
#endif
31
32
namespace {
33
34
static void addBCLib(const Driver &D, const ArgList &Args,
35
                     ArgStringList &CmdArgs, ArgStringList LibraryPaths,
36
228
                     StringRef BCName) {
37
228
  StringRef FullName;
38
228
  for (std::string LibraryPath : LibraryPaths) {
39
56
    SmallString<128> Path(LibraryPath);
40
56
    llvm::sys::path::append(Path, BCName);
41
56
    FullName = Path;
42
56
    if (llvm::sys::fs::exists(FullName)) {
43
45
      CmdArgs.push_back("-mlink-builtin-bitcode");
44
45
      CmdArgs.push_back(Args.MakeArgString(FullName));
45
45
      return;
46
45
    }
47
56
  }
48
228
  D.Diag(diag::err_drv_no_such_file) << BCName;
49
183
}
50
51
static const char *getOutputFileName(Compilation &C, StringRef Base,
52
                                     const char *Postfix,
53
106
                                     const char *Extension) {
54
106
  const char *OutputFileName;
55
106
  if (C.getDriver().isSaveTempsEnabled()) {
56
16
    OutputFileName =
57
16
        C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension);
58
90
  } else {
59
90
    std::string TmpName =
60
90
        C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension);
61
90
    OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName));
62
90
  }
63
106
  return OutputFileName;
64
106
}
65
66
static void addOptLevelArgs(const llvm::opt::ArgList &Args,
67
                            llvm::opt::ArgStringList &CmdArgs,
68
72
                            bool IsLlc = false) {
69
72
  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
70
14
    StringRef OOpt = "3";
71
14
    if (A->getOption().matches(options::OPT_O4) ||
72
14
        A->getOption().matches(options::OPT_Ofast))
73
0
      OOpt = "3";
74
14
    else if (A->getOption().matches(options::OPT_O0))
75
2
      OOpt = "0";
76
12
    else if (A->getOption().matches(options::OPT_O)) {
77
12
      // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3
78
12
      // so we map -Os/-Oz to -O2.
79
12
      // Only clang supports -Og, and maps it to -O1.
80
12
      // We map anything else to -O2.
81
12
      OOpt = llvm::StringSwitch<const char *>(A->getValue())
82
12
                 .Case("1", "1")
83
12
                 .Case("2", "2")
84
12
                 .Case("3", "3")
85
12
                 .Case("s", IsLlc ? 
"2"6
:
"s"6
)
86
12
                 .Case("z", IsLlc ? 
"2"6
:
"z"6
)
87
12
                 .Case("g", "1")
88
12
                 .Default("2");
89
12
    }
90
14
    CmdArgs.push_back(Args.MakeArgString("-O" + OOpt));
91
14
  }
92
72
}
93
} // namespace
94
95
const char *AMDGCN::Linker::constructLLVMLinkCommand(
96
    Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
97
    const ArgList &Args, StringRef SubArchName,
98
34
    StringRef OutputFilePrefix) const {
99
34
  ArgStringList CmdArgs;
100
34
  // Add the input bc's created by compile step.
101
34
  for (const auto &II : Inputs)
102
36
    CmdArgs.push_back(II.getFilename());
103
34
104
34
  // Add an intermediate output file.
105
34
  CmdArgs.push_back("-o");
106
34
  auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
107
34
  CmdArgs.push_back(OutputFileName);
108
34
  const char *Exec =
109
34
      Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
110
34
  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
111
34
  return OutputFileName;
112
34
}
113
114
const char *AMDGCN::Linker::constructOptCommand(
115
    Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
116
    const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
117
34
    llvm::StringRef OutputFilePrefix, const char *InputFileName) const {
118
34
  // Construct opt command.
119
34
  ArgStringList OptArgs;
120
34
  // The input to opt is the output from llvm-link.
121
34
  OptArgs.push_back(InputFileName);
122
34
  // Pass optimization arg to opt.
123
34
  addOptLevelArgs(Args, OptArgs);
124
34
  OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
125
34
  OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
126
34
127
34
  for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
128
2
    OptArgs.push_back(A->getValue(0));
129
2
  }
130
34
131
34
  OptArgs.push_back("-o");
132
34
  auto OutputFileName =
133
34
      getOutputFileName(C, OutputFilePrefix, "-optimized", "bc");
134
34
  OptArgs.push_back(OutputFileName);
135
34
  const char *OptExec =
136
34
      Args.MakeArgString(getToolChain().GetProgramPath("opt"));
137
34
  C.addCommand(std::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs));
138
34
  return OutputFileName;
139
34
}
140
141
const char *AMDGCN::Linker::constructLlcCommand(
142
    Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
143
    const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
144
    llvm::StringRef OutputFilePrefix, const char *InputFileName,
145
38
    bool OutputIsAsm) const {
146
38
  // Construct llc command.
147
38
  ArgStringList LlcArgs;
148
38
  // The input to llc is the output from opt.
149
38
  LlcArgs.push_back(InputFileName);
150
38
  // Pass optimization arg to llc.
151
38
  addOptLevelArgs(Args, LlcArgs, /*IsLlc=*/true);
152
38
  LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
153
38
  LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
154
38
  LlcArgs.push_back(
155
38
      Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? 
"asm"4
:
"obj"34
)));
156
38
157
38
  // Extract all the -m options
158
38
  std::vector<llvm::StringRef> Features;
159
38
  handleTargetFeaturesGroup(
160
38
    Args, Features, options::OPT_m_amdgpu_Features_Group);
161
38
162
38
  // Add features to mattr such as xnack
163
38
  std::string MAttrString = "-mattr=";
164
38
  for(auto OneFeature : Features) {
165
0
    MAttrString.append(Args.MakeArgString(OneFeature));
166
0
    if (OneFeature != Features.back())
167
0
      MAttrString.append(",");
168
0
  }
169
38
  if(!Features.empty())
170
0
    LlcArgs.push_back(Args.MakeArgString(MAttrString));
171
38
172
38
  for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
173
2
    LlcArgs.push_back(A->getValue(0));
174
2
  }
175
38
176
38
  // Add output filename
177
38
  LlcArgs.push_back("-o");
178
38
  auto LlcOutputFile =
179
38
      getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? 
"s"4
:
"o"34
);
180
38
  LlcArgs.push_back(LlcOutputFile);
181
38
  const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));
182
38
  C.addCommand(std::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs));
183
38
  return LlcOutputFile;
184
38
}
185
186
void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
187
                                          const InputInfoList &Inputs,
188
                                          const InputInfo &Output,
189
                                          const llvm::opt::ArgList &Args,
190
34
                                          const char *InputFileName) const {
191
34
  // Construct lld command.
192
34
  // The output from ld.lld is an HSA code object file.
193
34
  ArgStringList LldArgs{
194
34
      "-flavor", "gnu", "-shared", "-o", Output.getFilename(), InputFileName};
195
34
  const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
196
34
  C.addCommand(std::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs));
197
34
}
198
199
// Construct a clang-offload-bundler command to bundle code objects for
200
// different GPU's into a HIP fat binary.
201
void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
202
                  StringRef OutputFileName, const InputInfoList &Inputs,
203
30
                  const llvm::opt::ArgList &Args, const Tool& T) {
204
30
  // Construct clang-offload-bundler command to bundle object files for
205
30
  // for different GPU archs.
206
30
  ArgStringList BundlerArgs;
207
30
  BundlerArgs.push_back(Args.MakeArgString("-type=o"));
208
30
209
30
  // ToDo: Remove the dummy host binary entry which is required by
210
30
  // clang-offload-bundler.
211
30
  std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux";
212
30
  std::string BundlerInputArg = "-inputs=" NULL_FILE;
213
30
214
34
  for (const auto &II : Inputs) {
215
34
    const auto* A = II.getAction();
216
34
    BundlerTargetArg = BundlerTargetArg + ",hip-amdgcn-amd-amdhsa-" +
217
34
                       StringRef(A->getOffloadingArch()).str();
218
34
    BundlerInputArg = BundlerInputArg + "," + II.getFilename();
219
34
  }
220
30
  BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg));
221
30
  BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
222
30
223
30
  auto BundlerOutputArg = Args.MakeArgString(
224
30
      std::string("-outputs=").append(std::string(OutputFileName)));
225
30
  BundlerArgs.push_back(BundlerOutputArg);
226
30
227
30
  const char *Bundler = Args.MakeArgString(
228
30
      T.getToolChain().GetProgramPath("clang-offload-bundler"));
229
30
  C.addCommand(std::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs));
230
30
}
231
232
// For amdgcn the inputs of the linker job are device bitcode and output is
233
// object file. It calls llvm-link, opt, llc, then lld steps.
234
void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
235
                                   const InputInfo &Output,
236
                                   const InputInfoList &Inputs,
237
                                   const ArgList &Args,
238
61
                                   const char *LinkingOutput) const {
239
61
240
61
  if (JA.getType() == types::TY_HIP_FATBIN)
241
27
    return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this);
242
34
243
34
  assert(getToolChain().getTriple().getArch() == llvm::Triple::amdgcn &&
244
34
         "Unsupported target");
245
34
246
34
  std::string SubArchName = JA.getOffloadingArch();
247
34
  assert(StringRef(SubArchName).startswith("gfx") && "Unsupported sub arch");
248
34
249
34
  // Prefix for temporary file name.
250
34
  std::string Prefix = llvm::sys::path::stem(Inputs[0].getFilename()).str();
251
34
  if (!C.getDriver().isSaveTempsEnabled())
252
30
    Prefix += "-" + SubArchName;
253
34
254
34
  // Each command outputs different files.
255
34
  const char *LLVMLinkCommand =
256
34
      constructLLVMLinkCommand(C, JA, Inputs, Args, SubArchName, Prefix);
257
34
  const char *OptCommand = constructOptCommand(C, JA, Inputs, Args, SubArchName,
258
34
                                               Prefix, LLVMLinkCommand);
259
34
  if (C.getDriver().isSaveTempsEnabled())
260
4
    constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand,
261
4
                        /*OutputIsAsm=*/true);
262
34
  const char *LlcCommand =
263
34
      constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand);
264
34
  constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand);
265
34
}
266
267
HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple,
268
                             const ToolChain &HostTC, const ArgList &Args)
269
62
    : ToolChain(D, Triple, Args), HostTC(HostTC) {
270
62
  // Lookup binaries into the driver directory, this is used to
271
62
  // discover the clang-offload-bundler executable.
272
62
  getProgramPaths().push_back(getDriver().Dir);
273
62
}
274
275
void HIPToolChain::addClangTargetOptions(
276
    const llvm::opt::ArgList &DriverArgs,
277
    llvm::opt::ArgStringList &CC1Args,
278
61
    Action::OffloadKind DeviceOffloadingKind) const {
279
61
  HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
280
61
281
61
  StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
282
61
  assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
283
61
  (void) GpuArch;
284
61
  assert(DeviceOffloadingKind == Action::OFK_HIP &&
285
61
         "Only HIP offloading kinds are supported for GPUs.");
286
61
287
61
  CC1Args.push_back("-target-cpu");
288
61
  CC1Args.push_back(DriverArgs.MakeArgStringRef(GpuArch));
289
61
  CC1Args.push_back("-fcuda-is-device");
290
61
291
61
  if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
292
61
                         options::OPT_fno_cuda_approx_transcendentals, false))
293
0
    CC1Args.push_back("-fcuda-approx-transcendentals");
294
61
295
61
  if (DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
296
61
                         false))
297
23
    CC1Args.push_back("-fgpu-rdc");
298
61
299
61
  StringRef MaxThreadsPerBlock =
300
61
      DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ);
301
61
  if (!MaxThreadsPerBlock.empty()) {
302
1
    std::string ArgStr =
303
1
        std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str();
304
1
    CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr));
305
1
  }
306
61
307
61
  if (DriverArgs.hasFlag(options::OPT_fgpu_allow_device_init,
308
61
                         options::OPT_fno_gpu_allow_device_init, false))
309
0
    CC1Args.push_back("-fgpu-allow-device-init");
310
61
311
61
  CC1Args.push_back("-fcuda-allow-variadic-functions");
312
61
313
61
  // Default to "hidden" visibility, as object level linking will not be
314
61
  // supported for the foreseeable future.
315
61
  if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
316
61
                         options::OPT_fvisibility_ms_compat)) {
317
61
    CC1Args.append({"-fvisibility", "hidden"});
318
61
    CC1Args.push_back("-fapply-global-visibility-to-externs");
319
61
  }
320
61
321
61
  if (DriverArgs.hasArg(options::OPT_nogpulib))
322
25
    return;
323
36
  ArgStringList LibraryPaths;
324
36
325
36
  // Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
326
36
  for (auto Path :
327
36
       DriverArgs.getAllArgValues(options::OPT_hip_device_lib_path_EQ))
328
23
    LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
329
36
330
36
  addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
331
36
332
36
  llvm::SmallVector<std::string, 10> BCLibs;
333
36
334
36
  // Add bitcode library in --hip-device-lib.
335
36
  for (auto Lib : DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ)) {
336
21
    BCLibs.push_back(DriverArgs.MakeArgString(Lib));
337
21
  }
338
36
339
36
  // If --hip-device-lib is not set, add the default bitcode libraries.
340
36
  if (BCLibs.empty()) {
341
23
    // Get the bc lib file name for ISA version. For example,
342
23
    // gfx803 => oclc_isa_version_803.amdgcn.bc.
343
23
    std::string GFXVersion = GpuArch.drop_front(3).str();
344
23
    std::string ISAVerBC = "oclc_isa_version_" + GFXVersion + ".amdgcn.bc";
345
23
346
23
    llvm::StringRef FlushDenormalControlBC;
347
23
    if (DriverArgs.hasArg(options::OPT_fcuda_flush_denormals_to_zero))
348
1
      FlushDenormalControlBC = "oclc_daz_opt_on.amdgcn.bc";
349
22
    else
350
22
      FlushDenormalControlBC = "oclc_daz_opt_off.amdgcn.bc";
351
23
352
23
    llvm::StringRef WaveFrontSizeBC;
353
23
    if (stoi(GFXVersion) < 1000)
354
23
      WaveFrontSizeBC = "oclc_wavefrontsize64_on.amdgcn.bc";
355
0
    else
356
0
      WaveFrontSizeBC = "oclc_wavefrontsize64_off.amdgcn.bc";
357
23
358
23
    BCLibs.append({"hip.amdgcn.bc", "ocml.amdgcn.bc", "ockl.amdgcn.bc",
359
23
                   "oclc_finite_only_off.amdgcn.bc",
360
23
                   std::string(FlushDenormalControlBC),
361
23
                   "oclc_correctly_rounded_sqrt_on.amdgcn.bc",
362
23
                   "oclc_unsafe_math_off.amdgcn.bc", ISAVerBC,
363
23
                   std::string(WaveFrontSizeBC)});
364
23
  }
365
36
  for (auto Lib : BCLibs)
366
228
    addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib);
367
36
}
368
369
llvm::opt::DerivedArgList *
370
HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
371
                             StringRef BoundArch,
372
111
                             Action::OffloadKind DeviceOffloadKind) const {
373
111
  DerivedArgList *DAL =
374
111
      HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
375
111
  if (!DAL)
376
98
    DAL = new DerivedArgList(Args.getBaseArgs());
377
111
378
111
  const OptTable &Opts = getDriver().getOpts();
379
111
380
982
  for (Arg *A : Args) {
381
982
    if (A->getOption().matches(options::OPT_Xarch__)) {
382
1
      // Skip this argument unless the architecture matches BoundArch.
383
1
      if (BoundArch.empty() || A->getValue(0) != BoundArch)
384
0
        continue;
385
1
386
1
      unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
387
1
      unsigned Prev = Index;
388
1
      std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
389
1
390
1
      // If the argument parsing failed or more than one argument was
391
1
      // consumed, the -Xarch_ argument's parameter tried to consume
392
1
      // extra arguments. Emit an error and ignore.
393
1
      //
394
1
      // We also want to disallow any options which would alter the
395
1
      // driver behavior; that isn't going to work in our model. We
396
1
      // use isDriverOption() as an approximation, although things
397
1
      // like -O4 are going to slip through.
398
1
      if (!XarchArg || Index > Prev + 1) {
399
0
        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
400
0
            << A->getAsString(Args);
401
0
        continue;
402
1
      } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
403
0
        getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
404
0
            << A->getAsString(Args);
405
0
        continue;
406
0
      }
407
1
      XarchArg->setBaseArg(A);
408
1
      A = XarchArg.release();
409
1
      DAL->AddSynthesizedArg(A);
410
1
    }
411
982
    DAL->append(A);
412
982
  }
413
111
414
111
  if (!BoundArch.empty()) {
415
65
    DAL->eraseArg(options::OPT_march_EQ);
416
65
    DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
417
65
  }
418
111
419
111
  return DAL;
420
111
}
421
422
31
Tool *HIPToolChain::buildLinker() const {
423
31
  assert(getTriple().getArch() == llvm::Triple::amdgcn);
424
31
  return new tools::AMDGCN::Linker(*this);
425
31
}
426
427
61
void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
428
61
  HostTC.addClangWarningOptions(CC1Args);
429
61
}
430
431
ToolChain::CXXStdlibType
432
0
HIPToolChain::GetCXXStdlibType(const ArgList &Args) const {
433
0
  return HostTC.GetCXXStdlibType(Args);
434
0
}
435
436
void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
437
97
                                              ArgStringList &CC1Args) const {
438
97
  HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
439
97
}
440
441
void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
442
97
                                                 ArgStringList &CC1Args) const {
443
97
  HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
444
97
}
445
446
void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
447
0
                                        ArgStringList &CC1Args) const {
448
0
  HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
449
0
}
450
451
43
SanitizerMask HIPToolChain::getSupportedSanitizers() const {
452
43
  // The HIPToolChain only supports sanitizers in the sense that it allows
453
43
  // sanitizer arguments on the command line if they are supported by the host
454
43
  // toolchain. The HIPToolChain will actually ignore any command line
455
43
  // arguments for any of these "supported" sanitizers. That means that no
456
43
  // sanitization of device code is actually supported at this time.
457
43
  //
458
43
  // This behavior is necessary because the host and device toolchains
459
43
  // invocations often share the command line, so the device toolchain must
460
43
  // tolerate flags meant only for the host toolchain.
461
43
  return HostTC.getSupportedSanitizers();
462
43
}
463
464
VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D,
465
61
                                               const ArgList &Args) const {
466
61
  return HostTC.computeMSVCVersion(D, Args);
467
61
}