1fe6060f1SDimitry Andric //===- AMDGPUOpenMP.cpp - AMDGPUOpenMP ToolChain Implementation -*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #include "AMDGPUOpenMP.h" 10fe6060f1SDimitry Andric #include "AMDGPU.h" 11fe6060f1SDimitry Andric #include "CommonArgs.h" 12*69ade1e0SDimitry Andric #include "ToolChains/ROCm.h" 13fe6060f1SDimitry Andric #include "clang/Basic/DiagnosticDriver.h" 14fe6060f1SDimitry Andric #include "clang/Driver/Compilation.h" 15fe6060f1SDimitry Andric #include "clang/Driver/Driver.h" 16fe6060f1SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 17fe6060f1SDimitry Andric #include "clang/Driver/InputInfo.h" 18fe6060f1SDimitry Andric #include "clang/Driver/Options.h" 19*69ade1e0SDimitry Andric #include "llvm/ADT/STLExtras.h" 20fe6060f1SDimitry Andric #include "llvm/Support/FileSystem.h" 21fe6060f1SDimitry Andric #include "llvm/Support/FormatAdapters.h" 22fe6060f1SDimitry Andric #include "llvm/Support/FormatVariadic.h" 23fe6060f1SDimitry Andric #include "llvm/Support/Path.h" 24fe6060f1SDimitry Andric 25fe6060f1SDimitry Andric using namespace clang::driver; 26fe6060f1SDimitry Andric using namespace clang::driver::toolchains; 27fe6060f1SDimitry Andric using namespace clang::driver::tools; 28fe6060f1SDimitry Andric using namespace clang; 29fe6060f1SDimitry Andric using namespace llvm::opt; 30fe6060f1SDimitry Andric 31fe6060f1SDimitry Andric namespace { 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric static const char *getOutputFileName(Compilation &C, StringRef Base, 34fe6060f1SDimitry Andric const char *Postfix, 35fe6060f1SDimitry Andric const char *Extension) { 36fe6060f1SDimitry Andric const char *OutputFileName; 37fe6060f1SDimitry Andric if (C.getDriver().isSaveTempsEnabled()) { 38fe6060f1SDimitry Andric OutputFileName = 39fe6060f1SDimitry Andric C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension); 40fe6060f1SDimitry Andric } else { 41fe6060f1SDimitry Andric std::string TmpName = 42fe6060f1SDimitry Andric C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension); 43fe6060f1SDimitry Andric OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); 44fe6060f1SDimitry Andric } 45fe6060f1SDimitry Andric return OutputFileName; 46fe6060f1SDimitry Andric } 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric static void addLLCOptArg(const llvm::opt::ArgList &Args, 49fe6060f1SDimitry Andric llvm::opt::ArgStringList &CmdArgs) { 50fe6060f1SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { 51fe6060f1SDimitry Andric StringRef OOpt = "0"; 52fe6060f1SDimitry Andric if (A->getOption().matches(options::OPT_O4) || 53fe6060f1SDimitry Andric A->getOption().matches(options::OPT_Ofast)) 54fe6060f1SDimitry Andric OOpt = "3"; 55fe6060f1SDimitry Andric else if (A->getOption().matches(options::OPT_O0)) 56fe6060f1SDimitry Andric OOpt = "0"; 57fe6060f1SDimitry Andric else if (A->getOption().matches(options::OPT_O)) { 58fe6060f1SDimitry Andric // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3 59fe6060f1SDimitry Andric // so we map -Os/-Oz to -O2. 60fe6060f1SDimitry Andric // Only clang supports -Og, and maps it to -O1. 61fe6060f1SDimitry Andric // We map anything else to -O2. 62fe6060f1SDimitry Andric OOpt = llvm::StringSwitch<const char *>(A->getValue()) 63fe6060f1SDimitry Andric .Case("1", "1") 64fe6060f1SDimitry Andric .Case("2", "2") 65fe6060f1SDimitry Andric .Case("3", "3") 66fe6060f1SDimitry Andric .Case("s", "2") 67fe6060f1SDimitry Andric .Case("z", "2") 68fe6060f1SDimitry Andric .Case("g", "1") 69fe6060f1SDimitry Andric .Default("0"); 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); 72fe6060f1SDimitry Andric } 73fe6060f1SDimitry Andric } 74fe6060f1SDimitry Andric 75fe6060f1SDimitry Andric static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC, 76fe6060f1SDimitry Andric std::string &GPUArch) { 77fe6060f1SDimitry Andric if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) { 78fe6060f1SDimitry Andric std::string ErrMsg = 79fe6060f1SDimitry Andric llvm::formatv("{0}", llvm::fmt_consume(std::move(Err))); 80fe6060f1SDimitry Andric TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg; 81fe6060f1SDimitry Andric return false; 82fe6060f1SDimitry Andric } 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric return true; 85fe6060f1SDimitry Andric } 86fe6060f1SDimitry Andric } // namespace 87fe6060f1SDimitry Andric 88fe6060f1SDimitry Andric const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( 89*69ade1e0SDimitry Andric const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, 90*69ade1e0SDimitry Andric const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, 91*69ade1e0SDimitry Andric StringRef SubArchName, StringRef OutputFilePrefix) const { 92fe6060f1SDimitry Andric ArgStringList CmdArgs; 93fe6060f1SDimitry Andric 94fe6060f1SDimitry Andric for (const auto &II : Inputs) 95fe6060f1SDimitry Andric if (II.isFilename()) 96fe6060f1SDimitry Andric CmdArgs.push_back(II.getFilename()); 97*69ade1e0SDimitry Andric 98*69ade1e0SDimitry Andric if (Args.hasArg(options::OPT_l)) { 99*69ade1e0SDimitry Andric auto Lm = Args.getAllArgValues(options::OPT_l); 100*69ade1e0SDimitry Andric bool HasLibm = false; 101*69ade1e0SDimitry Andric for (auto &Lib : Lm) { 102*69ade1e0SDimitry Andric if (Lib == "m") { 103*69ade1e0SDimitry Andric HasLibm = true; 104*69ade1e0SDimitry Andric break; 105*69ade1e0SDimitry Andric } 106*69ade1e0SDimitry Andric } 107*69ade1e0SDimitry Andric 108*69ade1e0SDimitry Andric if (HasLibm) { 109*69ade1e0SDimitry Andric SmallVector<std::string, 12> BCLibs = 110*69ade1e0SDimitry Andric AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str()); 111*69ade1e0SDimitry Andric llvm::for_each(BCLibs, [&](StringRef BCFile) { 112*69ade1e0SDimitry Andric CmdArgs.push_back(Args.MakeArgString(BCFile)); 113*69ade1e0SDimitry Andric }); 114*69ade1e0SDimitry Andric } 115*69ade1e0SDimitry Andric } 116*69ade1e0SDimitry Andric 117fe6060f1SDimitry Andric // Add an intermediate output file. 118fe6060f1SDimitry Andric CmdArgs.push_back("-o"); 119fe6060f1SDimitry Andric const char *OutputFileName = 120fe6060f1SDimitry Andric getOutputFileName(C, OutputFilePrefix, "-linked", "bc"); 121fe6060f1SDimitry Andric CmdArgs.push_back(OutputFileName); 122fe6060f1SDimitry Andric const char *Exec = 123fe6060f1SDimitry Andric Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); 124fe6060f1SDimitry Andric C.addCommand(std::make_unique<Command>( 125fe6060f1SDimitry Andric JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, 126fe6060f1SDimitry Andric InputInfo(&JA, Args.MakeArgString(OutputFileName)))); 127fe6060f1SDimitry Andric return OutputFileName; 128fe6060f1SDimitry Andric } 129fe6060f1SDimitry Andric 130fe6060f1SDimitry Andric const char *AMDGCN::OpenMPLinker::constructLlcCommand( 131fe6060f1SDimitry Andric Compilation &C, const JobAction &JA, const InputInfoList &Inputs, 132fe6060f1SDimitry Andric const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, 133fe6060f1SDimitry Andric llvm::StringRef OutputFilePrefix, const char *InputFileName, 134fe6060f1SDimitry Andric bool OutputIsAsm) const { 135fe6060f1SDimitry Andric // Construct llc command. 136fe6060f1SDimitry Andric ArgStringList LlcArgs; 137fe6060f1SDimitry Andric // The input to llc is the output from opt. 138fe6060f1SDimitry Andric LlcArgs.push_back(InputFileName); 139fe6060f1SDimitry Andric // Pass optimization arg to llc. 140fe6060f1SDimitry Andric addLLCOptArg(Args, LlcArgs); 141fe6060f1SDimitry Andric LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); 142fe6060f1SDimitry Andric LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); 143fe6060f1SDimitry Andric LlcArgs.push_back( 144fe6060f1SDimitry Andric Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj"))); 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 147fe6060f1SDimitry Andric LlcArgs.push_back(A->getValue(0)); 148fe6060f1SDimitry Andric } 149fe6060f1SDimitry Andric 150fe6060f1SDimitry Andric // Add output filename 151fe6060f1SDimitry Andric LlcArgs.push_back("-o"); 152fe6060f1SDimitry Andric const char *LlcOutputFile = 153fe6060f1SDimitry Andric getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o"); 154fe6060f1SDimitry Andric LlcArgs.push_back(LlcOutputFile); 155fe6060f1SDimitry Andric const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc")); 156fe6060f1SDimitry Andric C.addCommand(std::make_unique<Command>( 157fe6060f1SDimitry Andric JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs, 158fe6060f1SDimitry Andric InputInfo(&JA, Args.MakeArgString(LlcOutputFile)))); 159fe6060f1SDimitry Andric return LlcOutputFile; 160fe6060f1SDimitry Andric } 161fe6060f1SDimitry Andric 162fe6060f1SDimitry Andric void AMDGCN::OpenMPLinker::constructLldCommand( 163fe6060f1SDimitry Andric Compilation &C, const JobAction &JA, const InputInfoList &Inputs, 164fe6060f1SDimitry Andric const InputInfo &Output, const llvm::opt::ArgList &Args, 165fe6060f1SDimitry Andric const char *InputFileName) const { 166fe6060f1SDimitry Andric // Construct lld command. 167fe6060f1SDimitry Andric // The output from ld.lld is an HSA code object file. 168fe6060f1SDimitry Andric ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", 169fe6060f1SDimitry Andric "-shared", "-o", Output.getFilename(), 170fe6060f1SDimitry Andric InputFileName}; 171fe6060f1SDimitry Andric 172fe6060f1SDimitry Andric const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); 173fe6060f1SDimitry Andric C.addCommand(std::make_unique<Command>( 174fe6060f1SDimitry Andric JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs, 175fe6060f1SDimitry Andric InputInfo(&JA, Args.MakeArgString(Output.getFilename())))); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric 178fe6060f1SDimitry Andric // For amdgcn the inputs of the linker job are device bitcode and output is 179fe6060f1SDimitry Andric // object file. It calls llvm-link, opt, llc, then lld steps. 180fe6060f1SDimitry Andric void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, 181fe6060f1SDimitry Andric const InputInfo &Output, 182fe6060f1SDimitry Andric const InputInfoList &Inputs, 183fe6060f1SDimitry Andric const ArgList &Args, 184fe6060f1SDimitry Andric const char *LinkingOutput) const { 185fe6060f1SDimitry Andric const ToolChain &TC = getToolChain(); 186fe6060f1SDimitry Andric assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target"); 187fe6060f1SDimitry Andric 188fe6060f1SDimitry Andric const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC = 189fe6060f1SDimitry Andric static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC); 190fe6060f1SDimitry Andric 191fe6060f1SDimitry Andric std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str(); 192fe6060f1SDimitry Andric if (GPUArch.empty()) { 193fe6060f1SDimitry Andric if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch)) 194fe6060f1SDimitry Andric return; 195fe6060f1SDimitry Andric } 196fe6060f1SDimitry Andric 197fe6060f1SDimitry Andric // Prefix for temporary file name. 198fe6060f1SDimitry Andric std::string Prefix; 199fe6060f1SDimitry Andric for (const auto &II : Inputs) 200fe6060f1SDimitry Andric if (II.isFilename()) 201fe6060f1SDimitry Andric Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch; 202fe6060f1SDimitry Andric assert(Prefix.length() && "no linker inputs are files "); 203fe6060f1SDimitry Andric 204fe6060f1SDimitry Andric // Each command outputs different files. 205*69ade1e0SDimitry Andric const char *LLVMLinkCommand = constructLLVMLinkCommand( 206*69ade1e0SDimitry Andric AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix); 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric // Produce readable assembly if save-temps is enabled. 209fe6060f1SDimitry Andric if (C.getDriver().isSaveTempsEnabled()) 210fe6060f1SDimitry Andric constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand, 211fe6060f1SDimitry Andric /*OutputIsAsm=*/true); 212fe6060f1SDimitry Andric const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch, 213fe6060f1SDimitry Andric Prefix, LLVMLinkCommand); 214fe6060f1SDimitry Andric constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand); 215fe6060f1SDimitry Andric } 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D, 218fe6060f1SDimitry Andric const llvm::Triple &Triple, 219fe6060f1SDimitry Andric const ToolChain &HostTC, 220fe6060f1SDimitry Andric const ArgList &Args) 221fe6060f1SDimitry Andric : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { 222fe6060f1SDimitry Andric // Lookup binaries into the driver directory, this is used to 223fe6060f1SDimitry Andric // discover the clang-offload-bundler executable. 224fe6060f1SDimitry Andric getProgramPaths().push_back(getDriver().Dir); 225fe6060f1SDimitry Andric } 226fe6060f1SDimitry Andric 227fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::addClangTargetOptions( 228fe6060f1SDimitry Andric const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, 229fe6060f1SDimitry Andric Action::OffloadKind DeviceOffloadingKind) const { 230fe6060f1SDimitry Andric HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); 231fe6060f1SDimitry Andric 232fe6060f1SDimitry Andric std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str(); 233fe6060f1SDimitry Andric if (GPUArch.empty()) { 234fe6060f1SDimitry Andric if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch)) 235fe6060f1SDimitry Andric return; 236fe6060f1SDimitry Andric } 237fe6060f1SDimitry Andric 238fe6060f1SDimitry Andric assert(DeviceOffloadingKind == Action::OFK_OpenMP && 239fe6060f1SDimitry Andric "Only OpenMP offloading kinds are supported."); 240fe6060f1SDimitry Andric 241fe6060f1SDimitry Andric CC1Args.push_back("-target-cpu"); 242fe6060f1SDimitry Andric CC1Args.push_back(DriverArgs.MakeArgStringRef(GPUArch)); 243fe6060f1SDimitry Andric CC1Args.push_back("-fcuda-is-device"); 244fe6060f1SDimitry Andric 245fe6060f1SDimitry Andric if (DriverArgs.hasArg(options::OPT_nogpulib)) 246fe6060f1SDimitry Andric return; 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric std::string BitcodeSuffix; 249fe6060f1SDimitry Andric if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, 250fe6060f1SDimitry Andric options::OPT_fno_openmp_target_new_runtime, false)) 251fe6060f1SDimitry Andric BitcodeSuffix = "new-amdgcn-" + GPUArch; 252fe6060f1SDimitry Andric else 253fe6060f1SDimitry Andric BitcodeSuffix = "amdgcn-" + GPUArch; 254fe6060f1SDimitry Andric 255fe6060f1SDimitry Andric addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, 256fe6060f1SDimitry Andric getTriple()); 257fe6060f1SDimitry Andric } 258fe6060f1SDimitry Andric 259fe6060f1SDimitry Andric llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( 260fe6060f1SDimitry Andric const llvm::opt::DerivedArgList &Args, StringRef BoundArch, 261fe6060f1SDimitry Andric Action::OffloadKind DeviceOffloadKind) const { 262fe6060f1SDimitry Andric DerivedArgList *DAL = 263fe6060f1SDimitry Andric HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); 264fe6060f1SDimitry Andric if (!DAL) 265fe6060f1SDimitry Andric DAL = new DerivedArgList(Args.getBaseArgs()); 266fe6060f1SDimitry Andric 267fe6060f1SDimitry Andric const OptTable &Opts = getDriver().getOpts(); 268fe6060f1SDimitry Andric 269fe6060f1SDimitry Andric if (DeviceOffloadKind != Action::OFK_OpenMP) { 270fe6060f1SDimitry Andric for (Arg *A : Args) { 271fe6060f1SDimitry Andric DAL->append(A); 272fe6060f1SDimitry Andric } 273fe6060f1SDimitry Andric } 274fe6060f1SDimitry Andric 275fe6060f1SDimitry Andric if (!BoundArch.empty()) { 276fe6060f1SDimitry Andric DAL->eraseArg(options::OPT_march_EQ); 277fe6060f1SDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), 278fe6060f1SDimitry Andric BoundArch); 279fe6060f1SDimitry Andric } 280fe6060f1SDimitry Andric 281fe6060f1SDimitry Andric return DAL; 282fe6060f1SDimitry Andric } 283fe6060f1SDimitry Andric 284fe6060f1SDimitry Andric Tool *AMDGPUOpenMPToolChain::buildLinker() const { 285fe6060f1SDimitry Andric assert(getTriple().isAMDGCN()); 286fe6060f1SDimitry Andric return new tools::AMDGCN::OpenMPLinker(*this); 287fe6060f1SDimitry Andric } 288fe6060f1SDimitry Andric 289fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::addClangWarningOptions( 290fe6060f1SDimitry Andric ArgStringList &CC1Args) const { 291fe6060f1SDimitry Andric HostTC.addClangWarningOptions(CC1Args); 292fe6060f1SDimitry Andric } 293fe6060f1SDimitry Andric 294fe6060f1SDimitry Andric ToolChain::CXXStdlibType 295fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::GetCXXStdlibType(const ArgList &Args) const { 296fe6060f1SDimitry Andric return HostTC.GetCXXStdlibType(Args); 297fe6060f1SDimitry Andric } 298fe6060f1SDimitry Andric 299fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::AddClangSystemIncludeArgs( 300fe6060f1SDimitry Andric const ArgList &DriverArgs, ArgStringList &CC1Args) const { 301fe6060f1SDimitry Andric HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); 302fe6060f1SDimitry Andric } 303fe6060f1SDimitry Andric 304fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, 305fe6060f1SDimitry Andric ArgStringList &CC1Args) const { 306fe6060f1SDimitry Andric HostTC.AddIAMCUIncludeArgs(Args, CC1Args); 307fe6060f1SDimitry Andric } 308fe6060f1SDimitry Andric 309fe6060f1SDimitry Andric SanitizerMask AMDGPUOpenMPToolChain::getSupportedSanitizers() const { 310fe6060f1SDimitry Andric // The AMDGPUOpenMPToolChain only supports sanitizers in the sense that it 311fe6060f1SDimitry Andric // allows sanitizer arguments on the command line if they are supported by the 312fe6060f1SDimitry Andric // host toolchain. The AMDGPUOpenMPToolChain will actually ignore any command 313fe6060f1SDimitry Andric // line arguments for any of these "supported" sanitizers. That means that no 314fe6060f1SDimitry Andric // sanitization of device code is actually supported at this time. 315fe6060f1SDimitry Andric // 316fe6060f1SDimitry Andric // This behavior is necessary because the host and device toolchains 317fe6060f1SDimitry Andric // invocations often share the command line, so the device toolchain must 318fe6060f1SDimitry Andric // tolerate flags meant only for the host toolchain. 319fe6060f1SDimitry Andric return HostTC.getSupportedSanitizers(); 320fe6060f1SDimitry Andric } 321fe6060f1SDimitry Andric 322fe6060f1SDimitry Andric VersionTuple 323fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D, 324fe6060f1SDimitry Andric const ArgList &Args) const { 325fe6060f1SDimitry Andric return HostTC.computeMSVCVersion(D, Args); 326fe6060f1SDimitry Andric } 327