| 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 | |
| 12 | using namespace clang::driver; |
| 13 | using namespace clang::driver::toolchains; |
| 14 | using namespace clang::driver::tools; |
| 15 | using namespace clang; |
| 16 | using namespace llvm::opt; |
| 17 | |
| 18 | SYCLInstallationDetector::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 | |
| 72 | void 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. |
| 86 | static 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 | |
| 112 | SYCLToolChain::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 | |
| 129 | void 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 | |
| 135 | llvm::opt::DerivedArgList * |
| 136 | SYCLToolChain::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 | |
| 183 | void SYCLToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { |
| 184 | HostTC.addClangWarningOptions(CC1Args); |
| 185 | } |
| 186 | |
| 187 | ToolChain::CXXStdlibType |
| 188 | SYCLToolChain::GetCXXStdlibType(const ArgList &Args) const { |
| 189 | return HostTC.GetCXXStdlibType(Args); |
| 190 | } |
| 191 | |
| 192 | void SYCLToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs, |
| 193 | ArgStringList &CC1Args) const { |
| 194 | SYCLInstallation.addSYCLIncludeArgs(DriverArgs, CC1Args); |
| 195 | } |
| 196 | |
| 197 | void SYCLToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
| 198 | ArgStringList &CC1Args) const { |
| 199 | HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); |
| 200 | } |
| 201 | |
| 202 | void SYCLToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, |
| 203 | ArgStringList &CC1Args) const { |
| 204 | HostTC.AddClangCXXStdlibIncludeArgs(DriverArgs: Args, CC1Args); |
| 205 | } |
| 206 | |