1//===--- SYCL.cpp - SYCL 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#include "SYCL.h"
9#include "clang/Driver/CommonArgs.h"
10#include "llvm/Support/VirtualFileSystem.h"
11
12using namespace clang::driver;
13using namespace clang::driver::toolchains;
14using namespace clang::driver::tools;
15using namespace clang;
16using namespace llvm::opt;
17
18SYCLInstallationDetector::SYCLInstallationDetector(
19 const Driver &D, const llvm::Triple &HostTriple,
20 const llvm::opt::ArgList &Args)
21 : D(D) {
22 // When -fsycl is active, locate the SYCL runtime library and record its
23 // directory in SYCLRTLibPath for use by the linker.
24 StringRef SysRoot = D.SysRoot;
25 SmallString<128> DriverDir(D.Dir);
26
27 if (HostTriple.isWindowsMSVCEnvironment() ||
28 HostTriple.isWindowsItaniumEnvironment()) {
29 // Windows: Check for LLVMSYCL.lib
30 // NOTE: Only checks for LLVMSYCL.lib existence (release variant).
31 // Debug vs release library selection happens at link time based on CRT
32 // flags.
33 if (DriverDir.starts_with(Prefix: SysRoot) &&
34 Args.hasFlag(Pos: options::OPT_fsycl, Neg: options::OPT_fno_sycl, Default: false)) {
35 SmallString<128> LibDir(DriverDir);
36 llvm::sys::path::append(path&: LibDir, a: "..", b: "lib");
37
38 // Verify SYCL runtime library exists
39 SmallString<128> SYCLLibPath(LibDir);
40 llvm::sys::path::append(path&: SYCLLibPath, a: "LLVMSYCL.lib");
41
42 if (D.getVFS().exists(Path: SYCLLibPath))
43 SYCLRTLibPath = LibDir;
44 }
45 } else {
46 // Linux/Unix: Check for libLLVMSYCL.so
47 SmallString<128> LibPath(DriverDir);
48 llvm::sys::path::append(path&: LibPath, a: "..", b: "lib", c: HostTriple.str(),
49 d: "libLLVMSYCL.so");
50 // Flat lib path for LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF builds,
51 // where the library is installed directly in lib/ with no triple subdir.
52 SmallString<128> FlatLibPath(DriverDir);
53 llvm::sys::path::append(path&: FlatLibPath, a: "..", b: "lib", c: "libLLVMSYCL.so");
54
55 if (DriverDir.starts_with(Prefix: SysRoot) &&
56 Args.hasFlag(Pos: options::OPT_fsycl, Neg: options::OPT_fno_sycl, Default: false)) {
57 // LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON: library is in lib/<triple>/
58 if (D.getVFS().exists(Path: LibPath))
59 llvm::sys::path::append(path&: DriverDir, a: "..", b: "lib", c: HostTriple.str());
60 // LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF: library is in lib/
61 else if (D.getVFS().exists(Path: FlatLibPath))
62 llvm::sys::path::append(path&: DriverDir, a: "..", b: "lib");
63 else
64 return; // Neither path exists : broken install, leave SYCLRTLibPath
65 // unset
66
67 SYCLRTLibPath = DriverDir;
68 }
69 }
70}
71
72void SYCLInstallationDetector::addSYCLIncludeArgs(
73 const ArgList &DriverArgs, ArgStringList &CC1Args) const {
74 if (DriverArgs.hasArg(Ids: options::OPT_nobuiltininc))
75 return;
76
77 // Add the SYCL header search locations.
78 // These are included for both SYCL host and device compilations.
79 SmallString<128> IncludePath(D.Dir);
80 llvm::sys::path::append(path&: IncludePath, a: "..", b: "include");
81 CC1Args.push_back(Elt: "-internal-isystem");
82 CC1Args.push_back(Elt: DriverArgs.MakeArgString(Str: IncludePath));
83}
84
85// Unsupported options for SYCL device compilation.
86static ArrayRef<options::ID> getUnsupportedOpts() {
87 static constexpr options::ID UnsupportedOpts[] = {
88 options::OPT_fsanitize_EQ, // -fsanitize
89 options::OPT_fcf_protection_EQ, // -fcf-protection
90 options::OPT_fprofile_generate,
91 options::OPT_fprofile_generate_EQ,
92 options::OPT_fno_profile_generate, // -f[no-]profile-generate
93 options::OPT_ftest_coverage,
94 options::OPT_fno_test_coverage, // -f[no-]test-coverage
95 options::OPT_fcoverage_mapping,
96 options::OPT_fno_coverage_mapping, // -f[no-]coverage-mapping
97 options::OPT_coverage, // --coverage
98 options::OPT_fprofile_instr_generate,
99 options::OPT_fprofile_instr_generate_EQ,
100 options::OPT_fno_profile_instr_generate, // -f[no-]profile-instr-generate
101 options::OPT_fprofile_arcs,
102 options::OPT_fno_profile_arcs, // -f[no-]profile-arcs
103 options::OPT_fcreate_profile, // -fcreate-profile
104 options::OPT_fprofile_instr_use,
105 options::OPT_fprofile_instr_use_EQ, // -fprofile-instr-use
106 options::OPT_fcs_profile_generate, // -fcs-profile-generate
107 options::OPT_fcs_profile_generate_EQ,
108 };
109 return UnsupportedOpts;
110}
111
112SYCLToolChain::SYCLToolChain(const Driver &D, const llvm::Triple &Triple,
113 const ToolChain &HostTC, const ArgList &Args)
114 : ToolChain(D, Triple, Args), HostTC(HostTC),
115 SYCLInstallation(D, Triple, Args) {
116 // Lookup binaries into the driver directory, this is used to discover any
117 // dependent SYCL offload compilation tools.
118 getProgramPaths().push_back(Elt: getDriver().Dir);
119
120 // Diagnose unsupported options only once.
121 for (OptSpecifier Opt : getUnsupportedOpts()) {
122 if (const Arg *A = Args.getLastArg(Ids: Opt)) {
123 D.Diag(DiagID: clang::diag::warn_drv_unsupported_option_for_target)
124 << A->getAsString(Args) << getTriple().str();
125 }
126 }
127}
128
129void SYCLToolChain::addClangTargetOptions(
130 const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
131 BoundArch BA, Action::OffloadKind DeviceOffloadingKind) const {
132 HostTC.addClangTargetOptions(DriverArgs, CC1Args, BA, DeviceOffloadKind: DeviceOffloadingKind);
133}
134
135llvm::opt::DerivedArgList *
136SYCLToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
137 BoundArch BA,
138 Action::OffloadKind DeviceOffloadKind) const {
139 DerivedArgList *DAL = HostTC.TranslateArgs(Args, BA, DeviceOffloadKind);
140
141 bool IsNewDAL = false;
142 if (!DAL) {
143 DAL = new DerivedArgList(Args.getBaseArgs());
144 IsNewDAL = true;
145 }
146
147 for (Arg *A : Args) {
148 // Filter out any options we do not want to pass along to the device
149 // compilation.
150 auto Opt(A->getOption());
151 bool Unsupported = false;
152 for (OptSpecifier UnsupportedOpt : getUnsupportedOpts()) {
153 if (Opt.matches(ID: UnsupportedOpt)) {
154 if (Opt.getID() == options::OPT_fsanitize_EQ &&
155 A->getValues().size() == 1) {
156 std::string SanitizeVal = A->getValue();
157 if (SanitizeVal == "address") {
158 if (IsNewDAL)
159 DAL->append(A);
160 continue;
161 }
162 }
163 if (!IsNewDAL)
164 DAL->eraseArg(Id: Opt.getID());
165 Unsupported = true;
166 }
167 }
168 if (Unsupported)
169 continue;
170 if (IsNewDAL)
171 DAL->append(A);
172 }
173
174 const OptTable &Opts = getDriver().getOpts();
175 if (BA) {
176 DAL->eraseArg(Id: options::OPT_march_EQ);
177 DAL->AddJoinedArg(BaseArg: nullptr, Opt: Opts.getOption(Opt: options::OPT_march_EQ),
178 Value: BA.ArchName);
179 }
180 return DAL;
181}
182
183void SYCLToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
184 HostTC.addClangWarningOptions(CC1Args);
185}
186
187ToolChain::CXXStdlibType
188SYCLToolChain::GetCXXStdlibType(const ArgList &Args) const {
189 return HostTC.GetCXXStdlibType(Args);
190}
191
192void SYCLToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs,
193 ArgStringList &CC1Args) const {
194 SYCLInstallation.addSYCLIncludeArgs(DriverArgs, CC1Args);
195}
196
197void SYCLToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
198 ArgStringList &CC1Args) const {
199 HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
200}
201
202void SYCLToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
203 ArgStringList &CC1Args) const {
204 HostTC.AddClangCXXStdlibIncludeArgs(DriverArgs: Args, CC1Args);
205}
206