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"
1904eeddc0SDimitry 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
AMDGPUOpenMPToolChain(const Driver & D,const llvm::Triple & Triple,const ToolChain & HostTC,const ArgList & Args)32fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D,
33fe6060f1SDimitry Andric const llvm::Triple &Triple,
34fe6060f1SDimitry Andric const ToolChain &HostTC,
35fe6060f1SDimitry Andric const ArgList &Args)
36fe6060f1SDimitry Andric : ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
37fe6060f1SDimitry Andric // Lookup binaries into the driver directory, this is used to
38*06c3fb27SDimitry Andric // discover the 'amdgpu-arch' executable.
39fe6060f1SDimitry Andric getProgramPaths().push_back(getDriver().Dir);
40fe6060f1SDimitry Andric }
41fe6060f1SDimitry Andric
addClangTargetOptions(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadingKind) const42fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::addClangTargetOptions(
43fe6060f1SDimitry Andric const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
44fe6060f1SDimitry Andric Action::OffloadKind DeviceOffloadingKind) const {
45fe6060f1SDimitry Andric HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
46fe6060f1SDimitry Andric
47bdd1243dSDimitry Andric StringRef GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
48bdd1243dSDimitry Andric assert(!GPUArch.empty() && "Must have an explicit GPU arch.");
49fe6060f1SDimitry Andric
50fe6060f1SDimitry Andric assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
51fe6060f1SDimitry Andric "Only OpenMP offloading kinds are supported.");
52fe6060f1SDimitry Andric
53fe6060f1SDimitry Andric CC1Args.push_back("-target-cpu");
54fe6060f1SDimitry Andric CC1Args.push_back(DriverArgs.MakeArgStringRef(GPUArch));
55fe6060f1SDimitry Andric CC1Args.push_back("-fcuda-is-device");
56fe6060f1SDimitry Andric
57fe6060f1SDimitry Andric if (DriverArgs.hasArg(options::OPT_nogpulib))
58fe6060f1SDimitry Andric return;
59fe6060f1SDimitry Andric
60bdd1243dSDimitry Andric for (auto BCFile : getDeviceLibs(DriverArgs)) {
61bdd1243dSDimitry Andric CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
62bdd1243dSDimitry Andric : "-mlink-bitcode-file");
63bdd1243dSDimitry Andric CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
64bdd1243dSDimitry Andric }
65bdd1243dSDimitry Andric
661fd87a68SDimitry Andric // Link the bitcode library late if we're using device LTO.
671fd87a68SDimitry Andric if (getDriver().isUsingLTO(/* IsOffload */ true))
681fd87a68SDimitry Andric return;
69fe6060f1SDimitry Andric }
70fe6060f1SDimitry Andric
TranslateArgs(const llvm::opt::DerivedArgList & Args,StringRef BoundArch,Action::OffloadKind DeviceOffloadKind) const71fe6060f1SDimitry Andric llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
72fe6060f1SDimitry Andric const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
73fe6060f1SDimitry Andric Action::OffloadKind DeviceOffloadKind) const {
74fe6060f1SDimitry Andric DerivedArgList *DAL =
75fe6060f1SDimitry Andric HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
76fe6060f1SDimitry Andric if (!DAL)
77fe6060f1SDimitry Andric DAL = new DerivedArgList(Args.getBaseArgs());
78fe6060f1SDimitry Andric
79fe6060f1SDimitry Andric const OptTable &Opts = getDriver().getOpts();
80fe6060f1SDimitry Andric
8104eeddc0SDimitry Andric if (DeviceOffloadKind == Action::OFK_OpenMP) {
8204eeddc0SDimitry Andric for (Arg *A : Args)
8304eeddc0SDimitry Andric if (!llvm::is_contained(*DAL, A))
8404eeddc0SDimitry Andric DAL->append(A);
8504eeddc0SDimitry Andric
8681ad6265SDimitry Andric if (!DAL->hasArg(options::OPT_march_EQ)) {
87bdd1243dSDimitry Andric StringRef Arch = BoundArch;
88bdd1243dSDimitry Andric if (Arch.empty()) {
89bdd1243dSDimitry Andric auto ArchsOrErr = getSystemGPUArchs(Args);
90bdd1243dSDimitry Andric if (!ArchsOrErr) {
91bdd1243dSDimitry Andric std::string ErrMsg =
92bdd1243dSDimitry Andric llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError()));
93bdd1243dSDimitry Andric getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
94bdd1243dSDimitry Andric << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march";
95bdd1243dSDimitry Andric Arch = CudaArchToString(CudaArch::HIPDefault);
96bdd1243dSDimitry Andric } else {
97bdd1243dSDimitry Andric Arch = Args.MakeArgString(ArchsOrErr->front());
98bdd1243dSDimitry Andric }
99bdd1243dSDimitry Andric }
10004eeddc0SDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
10104eeddc0SDimitry Andric }
10204eeddc0SDimitry Andric
10304eeddc0SDimitry Andric return DAL;
10404eeddc0SDimitry Andric }
10504eeddc0SDimitry Andric
106fe6060f1SDimitry Andric for (Arg *A : Args) {
107fe6060f1SDimitry Andric DAL->append(A);
108fe6060f1SDimitry Andric }
109fe6060f1SDimitry Andric
110fe6060f1SDimitry Andric if (!BoundArch.empty()) {
111fe6060f1SDimitry Andric DAL->eraseArg(options::OPT_march_EQ);
112fe6060f1SDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
113fe6060f1SDimitry Andric BoundArch);
114fe6060f1SDimitry Andric }
115fe6060f1SDimitry Andric
116fe6060f1SDimitry Andric return DAL;
117fe6060f1SDimitry Andric }
118fe6060f1SDimitry Andric
addClangWarningOptions(ArgStringList & CC1Args) const119fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::addClangWarningOptions(
120fe6060f1SDimitry Andric ArgStringList &CC1Args) const {
121fe6060f1SDimitry Andric HostTC.addClangWarningOptions(CC1Args);
122fe6060f1SDimitry Andric }
123fe6060f1SDimitry Andric
124fe6060f1SDimitry Andric ToolChain::CXXStdlibType
GetCXXStdlibType(const ArgList & Args) const125fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::GetCXXStdlibType(const ArgList &Args) const {
126fe6060f1SDimitry Andric return HostTC.GetCXXStdlibType(Args);
127fe6060f1SDimitry Andric }
128fe6060f1SDimitry Andric
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const129fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::AddClangSystemIncludeArgs(
130fe6060f1SDimitry Andric const ArgList &DriverArgs, ArgStringList &CC1Args) const {
131fe6060f1SDimitry Andric HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
132fe6060f1SDimitry Andric }
133fe6060f1SDimitry Andric
AddIAMCUIncludeArgs(const ArgList & Args,ArgStringList & CC1Args) const134fe6060f1SDimitry Andric void AMDGPUOpenMPToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
135fe6060f1SDimitry Andric ArgStringList &CC1Args) const {
136fe6060f1SDimitry Andric HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
137fe6060f1SDimitry Andric }
138fe6060f1SDimitry Andric
getSupportedSanitizers() const139fe6060f1SDimitry Andric SanitizerMask AMDGPUOpenMPToolChain::getSupportedSanitizers() const {
140fe6060f1SDimitry Andric // The AMDGPUOpenMPToolChain only supports sanitizers in the sense that it
141fe6060f1SDimitry Andric // allows sanitizer arguments on the command line if they are supported by the
142fe6060f1SDimitry Andric // host toolchain. The AMDGPUOpenMPToolChain will actually ignore any command
143fe6060f1SDimitry Andric // line arguments for any of these "supported" sanitizers. That means that no
144fe6060f1SDimitry Andric // sanitization of device code is actually supported at this time.
145fe6060f1SDimitry Andric //
146fe6060f1SDimitry Andric // This behavior is necessary because the host and device toolchains
147fe6060f1SDimitry Andric // invocations often share the command line, so the device toolchain must
148fe6060f1SDimitry Andric // tolerate flags meant only for the host toolchain.
149fe6060f1SDimitry Andric return HostTC.getSupportedSanitizers();
150fe6060f1SDimitry Andric }
151fe6060f1SDimitry Andric
152fe6060f1SDimitry Andric VersionTuple
computeMSVCVersion(const Driver * D,const ArgList & Args) const153fe6060f1SDimitry Andric AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D,
154fe6060f1SDimitry Andric const ArgList &Args) const {
155fe6060f1SDimitry Andric return HostTC.computeMSVCVersion(D, Args);
156fe6060f1SDimitry Andric }
157bdd1243dSDimitry Andric
158bdd1243dSDimitry Andric llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
getDeviceLibs(const llvm::opt::ArgList & Args) const159bdd1243dSDimitry Andric AMDGPUOpenMPToolChain::getDeviceLibs(const llvm::opt::ArgList &Args) const {
160bdd1243dSDimitry Andric if (Args.hasArg(options::OPT_nogpulib))
161bdd1243dSDimitry Andric return {};
162bdd1243dSDimitry Andric
163*06c3fb27SDimitry Andric if (!RocmInstallation->hasDeviceLibrary()) {
164bdd1243dSDimitry Andric getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
165bdd1243dSDimitry Andric return {};
166bdd1243dSDimitry Andric }
167bdd1243dSDimitry Andric
168bdd1243dSDimitry Andric StringRef GpuArch = getProcessorFromTargetID(
169bdd1243dSDimitry Andric getTriple(), Args.getLastArgValue(options::OPT_march_EQ));
170bdd1243dSDimitry Andric
171bdd1243dSDimitry Andric SmallVector<BitCodeLibraryInfo, 12> BCLibs;
172bdd1243dSDimitry Andric for (auto BCLib : getCommonDeviceLibNames(Args, GpuArch.str(),
173bdd1243dSDimitry Andric /*IsOpenMP=*/true))
174bdd1243dSDimitry Andric BCLibs.emplace_back(BCLib);
175bdd1243dSDimitry Andric
176bdd1243dSDimitry Andric return BCLibs;
177bdd1243dSDimitry Andric }
178