xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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"
1269ade1e0SDimitry 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*04eeddc0SDimitry Andric #include "clang/Driver/Tool.h"
2069ade1e0SDimitry Andric #include "llvm/ADT/STLExtras.h"
21fe6060f1SDimitry Andric #include "llvm/Support/FileSystem.h"
22fe6060f1SDimitry Andric #include "llvm/Support/FormatAdapters.h"
23fe6060f1SDimitry Andric #include "llvm/Support/FormatVariadic.h"
24fe6060f1SDimitry Andric #include "llvm/Support/Path.h"
25fe6060f1SDimitry Andric 
26fe6060f1SDimitry Andric using namespace clang::driver;
27fe6060f1SDimitry Andric using namespace clang::driver::toolchains;
28fe6060f1SDimitry Andric using namespace clang::driver::tools;
29fe6060f1SDimitry Andric using namespace clang;
30fe6060f1SDimitry Andric using namespace llvm::opt;
31fe6060f1SDimitry Andric 
32fe6060f1SDimitry Andric namespace {
33fe6060f1SDimitry Andric 
34fe6060f1SDimitry Andric static const char *getOutputFileName(Compilation &C, StringRef Base,
35fe6060f1SDimitry Andric                                      const char *Postfix,
36fe6060f1SDimitry Andric                                      const char *Extension) {
37fe6060f1SDimitry Andric   const char *OutputFileName;
38fe6060f1SDimitry Andric   if (C.getDriver().isSaveTempsEnabled()) {
39fe6060f1SDimitry Andric     OutputFileName =
40fe6060f1SDimitry Andric         C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension);
41fe6060f1SDimitry Andric   } else {
42fe6060f1SDimitry Andric     std::string TmpName =
43fe6060f1SDimitry Andric         C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension);
44fe6060f1SDimitry Andric     OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName));
45fe6060f1SDimitry Andric   }
46fe6060f1SDimitry Andric   return OutputFileName;
47fe6060f1SDimitry Andric }
48fe6060f1SDimitry Andric 
49fe6060f1SDimitry Andric static void addLLCOptArg(const llvm::opt::ArgList &Args,
50fe6060f1SDimitry Andric                          llvm::opt::ArgStringList &CmdArgs) {
51fe6060f1SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
52fe6060f1SDimitry Andric     StringRef OOpt = "0";
53fe6060f1SDimitry Andric     if (A->getOption().matches(options::OPT_O4) ||
54fe6060f1SDimitry Andric         A->getOption().matches(options::OPT_Ofast))
55fe6060f1SDimitry Andric       OOpt = "3";
56fe6060f1SDimitry Andric     else if (A->getOption().matches(options::OPT_O0))
57fe6060f1SDimitry Andric       OOpt = "0";
58fe6060f1SDimitry Andric     else if (A->getOption().matches(options::OPT_O)) {
59fe6060f1SDimitry Andric       // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3
60fe6060f1SDimitry Andric       // so we map -Os/-Oz to -O2.
61fe6060f1SDimitry Andric       // Only clang supports -Og, and maps it to -O1.
62fe6060f1SDimitry Andric       // We map anything else to -O2.
63fe6060f1SDimitry Andric       OOpt = llvm::StringSwitch<const char *>(A->getValue())
64fe6060f1SDimitry Andric                  .Case("1", "1")
65fe6060f1SDimitry Andric                  .Case("2", "2")
66fe6060f1SDimitry Andric                  .Case("3", "3")
67fe6060f1SDimitry Andric                  .Case("s", "2")
68fe6060f1SDimitry Andric                  .Case("z", "2")
69fe6060f1SDimitry Andric                  .Case("g", "1")
70fe6060f1SDimitry Andric                  .Default("0");
71fe6060f1SDimitry Andric     }
72fe6060f1SDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-O" + OOpt));
73fe6060f1SDimitry Andric   }
74fe6060f1SDimitry Andric }
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC,
77fe6060f1SDimitry Andric                                  std::string &GPUArch) {
78fe6060f1SDimitry Andric   if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) {
79fe6060f1SDimitry Andric     std::string ErrMsg =
80fe6060f1SDimitry Andric         llvm::formatv("{0}", llvm::fmt_consume(std::move(Err)));
81fe6060f1SDimitry Andric     TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg;
82fe6060f1SDimitry Andric     return false;
83fe6060f1SDimitry Andric   }
84fe6060f1SDimitry Andric 
85fe6060f1SDimitry Andric   return true;
86fe6060f1SDimitry Andric }
87fe6060f1SDimitry Andric } // namespace
88fe6060f1SDimitry Andric 
89fe6060f1SDimitry Andric const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
9069ade1e0SDimitry Andric     const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C,
9169ade1e0SDimitry Andric     const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args,
9269ade1e0SDimitry Andric     StringRef SubArchName, StringRef OutputFilePrefix) const {
93fe6060f1SDimitry Andric   ArgStringList CmdArgs;
94fe6060f1SDimitry Andric 
95fe6060f1SDimitry Andric   for (const auto &II : Inputs)
96fe6060f1SDimitry Andric     if (II.isFilename())
97fe6060f1SDimitry Andric       CmdArgs.push_back(II.getFilename());
9869ade1e0SDimitry Andric 
99*04eeddc0SDimitry Andric   bool HasLibm = false;
10069ade1e0SDimitry Andric   if (Args.hasArg(options::OPT_l)) {
10169ade1e0SDimitry Andric     auto Lm = Args.getAllArgValues(options::OPT_l);
10269ade1e0SDimitry Andric     for (auto &Lib : Lm) {
10369ade1e0SDimitry Andric       if (Lib == "m") {
10469ade1e0SDimitry Andric         HasLibm = true;
10569ade1e0SDimitry Andric         break;
10669ade1e0SDimitry Andric       }
10769ade1e0SDimitry Andric     }
10869ade1e0SDimitry Andric 
10969ade1e0SDimitry Andric     if (HasLibm) {
110349cc55cSDimitry Andric       // This is not certain to work. The device libs added here, and passed to
111349cc55cSDimitry Andric       // llvm-link, are missing attributes that they expect to be inserted when
112349cc55cSDimitry Andric       // passed to mlink-builtin-bitcode. The amdgpu backend does not generate
113349cc55cSDimitry Andric       // conservatively correct code when attributes are missing, so this may
114349cc55cSDimitry Andric       // be the root cause of miscompilations. Passing via mlink-builtin-bitcode
115349cc55cSDimitry Andric       // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes
116349cc55cSDimitry Andric       // on each function, see D28538 for context.
117349cc55cSDimitry Andric       // Potential workarounds:
118349cc55cSDimitry Andric       //  - unconditionally link all of the device libs to every translation
119349cc55cSDimitry Andric       //    unit in clang via mlink-builtin-bitcode
120349cc55cSDimitry Andric       //  - build a libm bitcode file as part of the DeviceRTL and explictly
121349cc55cSDimitry Andric       //    mlink-builtin-bitcode the rocm device libs components at build time
122349cc55cSDimitry Andric       //  - drop this llvm-link fork in favour or some calls into LLVM, chosen
123349cc55cSDimitry Andric       //    to do basically the same work as llvm-link but with that call first
124349cc55cSDimitry Andric       //  - write an opt pass that sets that on every function it sees and pipe
125349cc55cSDimitry Andric       //    the device-libs bitcode through that on the way to this llvm-link
12669ade1e0SDimitry Andric       SmallVector<std::string, 12> BCLibs =
12769ade1e0SDimitry Andric           AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str());
12869ade1e0SDimitry Andric       llvm::for_each(BCLibs, [&](StringRef BCFile) {
12969ade1e0SDimitry Andric         CmdArgs.push_back(Args.MakeArgString(BCFile));
13069ade1e0SDimitry Andric       });
13169ade1e0SDimitry Andric     }
13269ade1e0SDimitry Andric   }
13369ade1e0SDimitry Andric 
134349cc55cSDimitry Andric   AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn",
135*04eeddc0SDimitry Andric                              SubArchName, /*isBitCodeSDL=*/true,
136*04eeddc0SDimitry Andric                              /*postClangLink=*/false);
137fe6060f1SDimitry Andric   // Add an intermediate output file.
138fe6060f1SDimitry Andric   CmdArgs.push_back("-o");
139fe6060f1SDimitry Andric   const char *OutputFileName =
140fe6060f1SDimitry Andric       getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
141fe6060f1SDimitry Andric   CmdArgs.push_back(OutputFileName);
142fe6060f1SDimitry Andric   const char *Exec =
143fe6060f1SDimitry Andric       Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
144fe6060f1SDimitry Andric   C.addCommand(std::make_unique<Command>(
145fe6060f1SDimitry Andric       JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs,
146fe6060f1SDimitry Andric       InputInfo(&JA, Args.MakeArgString(OutputFileName))));
147*04eeddc0SDimitry Andric 
148*04eeddc0SDimitry Andric   // If we linked in libm definitions late we run another round of optimizations
149*04eeddc0SDimitry Andric   // to inline the definitions and fold what is foldable.
150*04eeddc0SDimitry Andric   if (HasLibm) {
151*04eeddc0SDimitry Andric     ArgStringList OptCmdArgs;
152*04eeddc0SDimitry Andric     const char *OptOutputFileName =
153*04eeddc0SDimitry Andric         getOutputFileName(C, OutputFilePrefix, "-linked-opt", "bc");
154*04eeddc0SDimitry Andric     addLLCOptArg(Args, OptCmdArgs);
155*04eeddc0SDimitry Andric     OptCmdArgs.push_back(OutputFileName);
156*04eeddc0SDimitry Andric     OptCmdArgs.push_back("-o");
157*04eeddc0SDimitry Andric     OptCmdArgs.push_back(OptOutputFileName);
158*04eeddc0SDimitry Andric     const char *OptExec =
159*04eeddc0SDimitry Andric         Args.MakeArgString(getToolChain().GetProgramPath("opt"));
160*04eeddc0SDimitry Andric     C.addCommand(std::make_unique<Command>(
161*04eeddc0SDimitry Andric         JA, *this, ResponseFileSupport::AtFileCurCP(), OptExec, OptCmdArgs,
162*04eeddc0SDimitry Andric         InputInfo(&JA, Args.MakeArgString(OutputFileName)),
163*04eeddc0SDimitry Andric         InputInfo(&JA, Args.MakeArgString(OptOutputFileName))));
164*04eeddc0SDimitry Andric     OutputFileName = OptOutputFileName;
165*04eeddc0SDimitry Andric   }
166*04eeddc0SDimitry Andric 
167fe6060f1SDimitry Andric   return OutputFileName;
168fe6060f1SDimitry Andric }
169fe6060f1SDimitry Andric 
170fe6060f1SDimitry Andric const char *AMDGCN::OpenMPLinker::constructLlcCommand(
171fe6060f1SDimitry Andric     Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
172fe6060f1SDimitry Andric     const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
173fe6060f1SDimitry Andric     llvm::StringRef OutputFilePrefix, const char *InputFileName,
174fe6060f1SDimitry Andric     bool OutputIsAsm) const {
175fe6060f1SDimitry Andric   // Construct llc command.
176fe6060f1SDimitry Andric   ArgStringList LlcArgs;
177fe6060f1SDimitry Andric   // The input to llc is the output from opt.
178fe6060f1SDimitry Andric   LlcArgs.push_back(InputFileName);
179fe6060f1SDimitry Andric   // Pass optimization arg to llc.
180fe6060f1SDimitry Andric   addLLCOptArg(Args, LlcArgs);
181fe6060f1SDimitry Andric   LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
182fe6060f1SDimitry Andric   LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
183fe6060f1SDimitry Andric   LlcArgs.push_back(
184fe6060f1SDimitry Andric       Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")));
185fe6060f1SDimitry Andric 
186fe6060f1SDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
187fe6060f1SDimitry Andric     LlcArgs.push_back(A->getValue(0));
188fe6060f1SDimitry Andric   }
189fe6060f1SDimitry Andric 
190fe6060f1SDimitry Andric   // Add output filename
191fe6060f1SDimitry Andric   LlcArgs.push_back("-o");
192fe6060f1SDimitry Andric   const char *LlcOutputFile =
193fe6060f1SDimitry Andric       getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");
194fe6060f1SDimitry Andric   LlcArgs.push_back(LlcOutputFile);
195fe6060f1SDimitry Andric   const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));
196fe6060f1SDimitry Andric   C.addCommand(std::make_unique<Command>(
197fe6060f1SDimitry Andric       JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs,
198fe6060f1SDimitry Andric       InputInfo(&JA, Args.MakeArgString(LlcOutputFile))));
199fe6060f1SDimitry Andric   return LlcOutputFile;
200fe6060f1SDimitry Andric }
201fe6060f1SDimitry Andric 
202fe6060f1SDimitry Andric void AMDGCN::OpenMPLinker::constructLldCommand(
203fe6060f1SDimitry Andric     Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
204fe6060f1SDimitry Andric     const InputInfo &Output, const llvm::opt::ArgList &Args,
205fe6060f1SDimitry Andric     const char *InputFileName) const {
206fe6060f1SDimitry Andric   // Construct lld command.
207fe6060f1SDimitry Andric   // The output from ld.lld is an HSA code object file.
208fe6060f1SDimitry Andric   ArgStringList LldArgs{"-flavor",    "gnu", "--no-undefined",
209fe6060f1SDimitry Andric                         "-shared",    "-o",  Output.getFilename(),
210fe6060f1SDimitry Andric                         InputFileName};
211fe6060f1SDimitry Andric 
212fe6060f1SDimitry Andric   const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
213fe6060f1SDimitry Andric   C.addCommand(std::make_unique<Command>(
214fe6060f1SDimitry Andric       JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs,
215fe6060f1SDimitry Andric       InputInfo(&JA, Args.MakeArgString(Output.getFilename()))));
216fe6060f1SDimitry Andric }
217fe6060f1SDimitry Andric 
218fe6060f1SDimitry Andric // For amdgcn the inputs of the linker job are device bitcode and output is
219fe6060f1SDimitry Andric // object file. It calls llvm-link, opt, llc, then lld steps.
220fe6060f1SDimitry Andric void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
221fe6060f1SDimitry Andric                                         const InputInfo &Output,
222fe6060f1SDimitry Andric                                         const InputInfoList &Inputs,
223fe6060f1SDimitry Andric                                         const ArgList &Args,
224fe6060f1SDimitry Andric                                         const char *LinkingOutput) const {
225fe6060f1SDimitry Andric   const ToolChain &TC = getToolChain();
226fe6060f1SDimitry Andric   assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target");
227fe6060f1SDimitry Andric 
228fe6060f1SDimitry Andric   const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC =
229fe6060f1SDimitry Andric       static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC);
230fe6060f1SDimitry Andric 
231fe6060f1SDimitry Andric   std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str();
232fe6060f1SDimitry Andric   if (GPUArch.empty()) {
233fe6060f1SDimitry Andric     if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch))
234fe6060f1SDimitry Andric       return;
235fe6060f1SDimitry Andric   }
236fe6060f1SDimitry Andric 
237fe6060f1SDimitry Andric   // Prefix for temporary file name.
238fe6060f1SDimitry Andric   std::string Prefix;
239fe6060f1SDimitry Andric   for (const auto &II : Inputs)
240fe6060f1SDimitry Andric     if (II.isFilename())
241fe6060f1SDimitry Andric       Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch;
242fe6060f1SDimitry Andric   assert(Prefix.length() && "no linker inputs are files ");
243fe6060f1SDimitry Andric 
244fe6060f1SDimitry Andric   // Each command outputs different files.
24569ade1e0SDimitry Andric   const char *LLVMLinkCommand = constructLLVMLinkCommand(
24669ade1e0SDimitry Andric       AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix);
247fe6060f1SDimitry Andric 
248fe6060f1SDimitry Andric   // Produce readable assembly if save-temps is enabled.
249fe6060f1SDimitry Andric   if (C.getDriver().isSaveTempsEnabled())
250fe6060f1SDimitry Andric     constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand,
251fe6060f1SDimitry Andric                         /*OutputIsAsm=*/true);
252fe6060f1SDimitry Andric   const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch,
253fe6060f1SDimitry Andric                                                Prefix, LLVMLinkCommand);
254fe6060f1SDimitry Andric   constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand);
255fe6060f1SDimitry Andric }
256fe6060f1SDimitry Andric 
257fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D,
258fe6060f1SDimitry Andric                                              const llvm::Triple &Triple,
259fe6060f1SDimitry Andric                                              const ToolChain &HostTC,
260fe6060f1SDimitry Andric                                              const ArgList &Args)
261fe6060f1SDimitry Andric     : ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
262fe6060f1SDimitry Andric   // Lookup binaries into the driver directory, this is used to
263fe6060f1SDimitry Andric   // discover the clang-offload-bundler executable.
264fe6060f1SDimitry Andric   getProgramPaths().push_back(getDriver().Dir);
265fe6060f1SDimitry Andric }
266fe6060f1SDimitry Andric 
267fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::addClangTargetOptions(
268fe6060f1SDimitry Andric     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
269fe6060f1SDimitry Andric     Action::OffloadKind DeviceOffloadingKind) const {
270fe6060f1SDimitry Andric   HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
271fe6060f1SDimitry Andric 
272fe6060f1SDimitry Andric   std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str();
273fe6060f1SDimitry Andric   if (GPUArch.empty()) {
274fe6060f1SDimitry Andric     if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch))
275fe6060f1SDimitry Andric       return;
276fe6060f1SDimitry Andric   }
277fe6060f1SDimitry Andric 
278fe6060f1SDimitry Andric   assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
279fe6060f1SDimitry Andric          "Only OpenMP offloading kinds are supported.");
280fe6060f1SDimitry Andric 
281fe6060f1SDimitry Andric   CC1Args.push_back("-target-cpu");
282fe6060f1SDimitry Andric   CC1Args.push_back(DriverArgs.MakeArgStringRef(GPUArch));
283fe6060f1SDimitry Andric   CC1Args.push_back("-fcuda-is-device");
284fe6060f1SDimitry Andric 
285fe6060f1SDimitry Andric   if (DriverArgs.hasArg(options::OPT_nogpulib))
286fe6060f1SDimitry Andric     return;
287fe6060f1SDimitry Andric 
288fe6060f1SDimitry Andric   std::string BitcodeSuffix;
289fe6060f1SDimitry Andric   if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime,
2900eae32dcSDimitry Andric                          options::OPT_fno_openmp_target_new_runtime, true))
291349cc55cSDimitry Andric     BitcodeSuffix = "new-amdgpu-" + GPUArch;
292fe6060f1SDimitry Andric   else
293fe6060f1SDimitry Andric     BitcodeSuffix = "amdgcn-" + GPUArch;
294fe6060f1SDimitry Andric 
295fe6060f1SDimitry Andric   addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix,
296fe6060f1SDimitry Andric                      getTriple());
297fe6060f1SDimitry Andric }
298fe6060f1SDimitry Andric 
299fe6060f1SDimitry Andric llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
300fe6060f1SDimitry Andric     const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
301fe6060f1SDimitry Andric     Action::OffloadKind DeviceOffloadKind) const {
302fe6060f1SDimitry Andric   DerivedArgList *DAL =
303fe6060f1SDimitry Andric       HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
304fe6060f1SDimitry Andric   if (!DAL)
305fe6060f1SDimitry Andric     DAL = new DerivedArgList(Args.getBaseArgs());
306fe6060f1SDimitry Andric 
307fe6060f1SDimitry Andric   const OptTable &Opts = getDriver().getOpts();
308fe6060f1SDimitry Andric 
309*04eeddc0SDimitry Andric   if (DeviceOffloadKind == Action::OFK_OpenMP) {
310*04eeddc0SDimitry Andric     for (Arg *A : Args)
311*04eeddc0SDimitry Andric       if (!llvm::is_contained(*DAL, A))
312*04eeddc0SDimitry Andric         DAL->append(A);
313*04eeddc0SDimitry Andric 
314*04eeddc0SDimitry Andric     std::string Arch = DAL->getLastArgValue(options::OPT_march_EQ).str();
315*04eeddc0SDimitry Andric     if (Arch.empty()) {
316*04eeddc0SDimitry Andric       checkSystemForAMDGPU(Args, *this, Arch);
317*04eeddc0SDimitry Andric       DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
318*04eeddc0SDimitry Andric     }
319*04eeddc0SDimitry Andric 
320*04eeddc0SDimitry Andric     return DAL;
321*04eeddc0SDimitry Andric   }
322*04eeddc0SDimitry Andric 
323fe6060f1SDimitry Andric   for (Arg *A : Args) {
324fe6060f1SDimitry Andric     DAL->append(A);
325fe6060f1SDimitry Andric   }
326fe6060f1SDimitry Andric 
327fe6060f1SDimitry Andric   if (!BoundArch.empty()) {
328fe6060f1SDimitry Andric     DAL->eraseArg(options::OPT_march_EQ);
329fe6060f1SDimitry Andric     DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
330fe6060f1SDimitry Andric                       BoundArch);
331fe6060f1SDimitry Andric   }
332fe6060f1SDimitry Andric 
333fe6060f1SDimitry Andric   return DAL;
334fe6060f1SDimitry Andric }
335fe6060f1SDimitry Andric 
336fe6060f1SDimitry Andric Tool *AMDGPUOpenMPToolChain::buildLinker() const {
337fe6060f1SDimitry Andric   assert(getTriple().isAMDGCN());
338fe6060f1SDimitry Andric   return new tools::AMDGCN::OpenMPLinker(*this);
339fe6060f1SDimitry Andric }
340fe6060f1SDimitry Andric 
341fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::addClangWarningOptions(
342fe6060f1SDimitry Andric     ArgStringList &CC1Args) const {
343fe6060f1SDimitry Andric   HostTC.addClangWarningOptions(CC1Args);
344fe6060f1SDimitry Andric }
345fe6060f1SDimitry Andric 
346fe6060f1SDimitry Andric ToolChain::CXXStdlibType
347fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::GetCXXStdlibType(const ArgList &Args) const {
348fe6060f1SDimitry Andric   return HostTC.GetCXXStdlibType(Args);
349fe6060f1SDimitry Andric }
350fe6060f1SDimitry Andric 
351fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::AddClangSystemIncludeArgs(
352fe6060f1SDimitry Andric     const ArgList &DriverArgs, ArgStringList &CC1Args) const {
353fe6060f1SDimitry Andric   HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
354fe6060f1SDimitry Andric }
355fe6060f1SDimitry Andric 
356fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
357fe6060f1SDimitry Andric                                                 ArgStringList &CC1Args) const {
358fe6060f1SDimitry Andric   HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
359fe6060f1SDimitry Andric }
360fe6060f1SDimitry Andric 
361fe6060f1SDimitry Andric SanitizerMask AMDGPUOpenMPToolChain::getSupportedSanitizers() const {
362fe6060f1SDimitry Andric   // The AMDGPUOpenMPToolChain only supports sanitizers in the sense that it
363fe6060f1SDimitry Andric   // allows sanitizer arguments on the command line if they are supported by the
364fe6060f1SDimitry Andric   // host toolchain. The AMDGPUOpenMPToolChain will actually ignore any command
365fe6060f1SDimitry Andric   // line arguments for any of these "supported" sanitizers. That means that no
366fe6060f1SDimitry Andric   // sanitization of device code is actually supported at this time.
367fe6060f1SDimitry Andric   //
368fe6060f1SDimitry Andric   // This behavior is necessary because the host and device toolchains
369fe6060f1SDimitry Andric   // invocations often share the command line, so the device toolchain must
370fe6060f1SDimitry Andric   // tolerate flags meant only for the host toolchain.
371fe6060f1SDimitry Andric   return HostTC.getSupportedSanitizers();
372fe6060f1SDimitry Andric }
373fe6060f1SDimitry Andric 
374fe6060f1SDimitry Andric VersionTuple
375fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D,
376fe6060f1SDimitry Andric                                           const ArgList &Args) const {
377fe6060f1SDimitry Andric   return HostTC.computeMSVCVersion(D, Args);
378fe6060f1SDimitry Andric }
379