diff --git a/clang/include/clang/Driver/SyclInstallationDetector.h b/clang/include/clang/Driver/SyclInstallationDetector.h index 75b83e873020..e3924127a2bb 100644 --- a/clang/include/clang/Driver/SyclInstallationDetector.h +++ b/clang/include/clang/Driver/SyclInstallationDetector.h @@ -33,6 +33,12 @@ class SYCLInstallationDetector { void getSYCLDeviceLibPath( llvm::SmallVector, 4> &DeviceLibPaths) const; + + /// \brief Search the SYCL device library locations for \p LibName. + /// \return The full path to the library if found, otherwise std::nullopt. + std::optional> + findSYCLDeviceLib(llvm::StringRef LibName) const; + void addSYCLIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index aa9b09a80803..02b446d1f466 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -11556,18 +11556,11 @@ static void getNonTripleBasedSYCLPostLinkOpts(const ToolChain &TC, if (TC.getTriple().isSPIROrSPIRV() && !TC.getTriple().isSPIRAOT()) { SYCLInstallationDetector SYCLInstall(TC.getDriver(), TC.getTriple(), TCArgs); - SmallVector, 4> DeviceLibLocCandidates; - SmallString<128> NativeBfloat16Name("libsycl-native-bfloat16.bc"); - SYCLInstall.getSYCLDeviceLibPath(DeviceLibLocCandidates); - for (const auto &DeviceLibLoc : DeviceLibLocCandidates) { - SmallString<128> FullLibName(DeviceLibLoc); - llvm::sys::path::append(FullLibName, NativeBfloat16Name); - if (llvm::sys::fs::exists(FullLibName)) { - SmallString<128> SYCLDeviceLibDir("--device-lib-dir="); - SYCLDeviceLibDir += DeviceLibLoc.str(); - addArgs(PostLinkArgs, TCArgs, {SYCLDeviceLibDir.str()}); - break; - } + if (auto FullLibName = + SYCLInstall.findSYCLDeviceLib("libsycl-native-bfloat16.bc")) { + SmallString<128> SYCLDeviceLibDir("--device-lib-dir="); + SYCLDeviceLibDir += llvm::sys::path::parent_path(*FullLibName); + addArgs(PostLinkArgs, TCArgs, {SYCLDeviceLibDir.str()}); } } } @@ -12256,67 +12249,47 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, /*default=*/true)) CmdArgs.push_back("--no-sycl-rdc"); - // -sycl-device-library-location= provides the location in which the - // SYCL device libraries can be found. - SmallString<128> DeviceLibDir(D.Dir); - llvm::sys::path::append(DeviceLibDir, "..", "lib"); - // Check the library location candidates for the the libsycl-crt library - // and use that location. Base the location on relative to driver if this - // is not resolved. - SmallVector, 4> LibLocCandidates; SYCLInstallationDetector SYCLInstallation(D, getToolChain().getTriple(), Args); - SYCLInstallation.getSYCLDeviceLibPath(LibLocCandidates); - SmallString<128> LibName("libsycl-crt.bc"); - for (const auto &LibLoc : LibLocCandidates) { - SmallString<128> FullLibName(LibLoc); - llvm::sys::path::append(FullLibName, LibName); - if (llvm::sys::fs::exists(FullLibName)) { - DeviceLibDir = LibLoc; - break; - } - } // Device libraries for SYCL offloading are specified using // --bitcode-library== for each library. - // The full path must be provided (not relative to - // -sycl-device-library-location). // // Note: SPIR/SPIRV device libraries are linked at compile time using // -mlink-builtin-bitcode, so they are not passed here. Only non-SPIR - // targets (NVPTX, AMD) pass device libraries to clang-linker-wrapper. + // targets (NVPTX, AMD, NativeCPU) pass device libraries to + // clang-linker-wrapper. SmallVector BCLibList; + bool HasNativeCPU = false; auto ToolChainRange = C.getOffloadToolChains(); for (const auto &[Kind, TC] : llvm::make_range(ToolChainRange.first, ToolChainRange.second)) { llvm::Triple TargetTriple = TC->getTriple(); - SmallVector SYCLDeviceLibs; + HasNativeCPU |= TargetTriple.isNativeCPU(); // SPIR or SPIR-V device libraries are compiled into the device compile - // step. Non-SPIR here means NVPTX/AMDGCN (CudaToolChain/AMDGPUToolChain). + // step. Non-SPIR here means NVPTX/AMDGCN (CudaToolChain/AMDGPUToolChain) + // or NativeCPU. if (!TargetTriple.isSPIROrSPIRV()) { const ToolChain *HostTC = C.getSingleOffloadToolChain(); std::unique_ptr ScratchTC; const toolchains::SYCLToolChain &SYCLTC = toolchains::getSYCLToolChain(D, *TC, *HostTC, Args, ScratchTC); - SYCLDeviceLibs.append(SYCLTC.getDeviceLibNames(D, Args, TargetTriple)); - } - for (const auto &AddLib : SYCLDeviceLibs) { - if (llvm::sys::path::extension(AddLib.Path) == ".bc") { - SmallString<256> LibPath(DeviceLibDir); - llvm::sys::path::append(LibPath, AddLib.Path); - BCLibList.push_back( - (Twine(TC->getTriple().str()) + "=" + LibPath).str()); - continue; - } + // getDeviceLibs resolves the full path of each library and diagnoses + // any that are not found. + for (const auto &AddLib : + SYCLTC.getDeviceLibs(Args, /*BA=*/{}, Action::OFK_SYCL)) + if (llvm::sys::path::extension(AddLib.Path) == ".bc") + BCLibList.push_back( + (Twine(TargetTriple.str()) + "=" + AddLib.Path).str()); } - if (TC->getTriple().isNVPTX()) + if (TargetTriple.isNVPTX()) if (const char *LibSpirvFile = SYCLInstallation.findLibspirvPath( - TC->getTriple(), Args, *TC->getAuxTriple())) + TargetTriple, Args, *TC->getAuxTriple())) BCLibList.push_back( - (Twine(TC->getTriple().str()) + "=" + LibSpirvFile).str()); + (Twine(TargetTriple.str()) + "=" + LibSpirvFile).str()); } if (BCLibList.size()) @@ -12324,6 +12297,14 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(Twine("--bitcode-library=") + Lib)); + // -sycl-device-library-location= provides the location of the + // native CPU/bfloat16 device libraries. Falls back to /../lib. + SmallString<128> DeviceLibDir(D.Dir); + llvm::sys::path::append(DeviceLibDir, "..", "lib"); + if (auto FullLibName = SYCLInstallation.findSYCLDeviceLib( + HasNativeCPU ? "libsycl-nativecpu_utils.bc" + : "libsycl-native-bfloat16.bc")) + DeviceLibDir = llvm::sys::path::parent_path(*FullLibName); CmdArgs.push_back(Args.MakeArgString( Twine("-sycl-device-library-location=") + DeviceLibDir)); diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index f00a39aa8238..ed765b289e82 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -198,6 +198,19 @@ void SYCLInstallationDetector::getSYCLDeviceLibPath( DeviceLibPaths.emplace_back(Path.str()); } +std::optional> +SYCLInstallationDetector::findSYCLDeviceLib(StringRef LibName) const { + SmallVector, 4> DeviceLibPaths; + getSYCLDeviceLibPath(DeviceLibPaths); + for (const auto &LibPath : DeviceLibPaths) { + SmallString<128> FullLibName(LibPath); + llvm::sys::path::append(FullLibName, LibName); + if (D.getVFS().exists(FullLibName)) + return FullLibName; + } + return std::nullopt; +} + void SYCLInstallationDetector::addSYCLIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc)) { @@ -2075,9 +2088,6 @@ SYCLToolChain::getDeviceLibs( const Action::OffloadKind DeviceOffloadingKind) const { llvm::SmallVector BCLibs; - SmallVector, 4> LibraryPaths; - SYCLInstallation.getSYCLDeviceLibPath(LibraryPaths); - // Formulate all of the device libraries needed for this compilation. SmallVector DeviceLibs = getDeviceLibNames(getDriver(), DriverArgs, getTriple()); @@ -2085,21 +2095,12 @@ SYCLToolChain::getDeviceLibs( // Create full path names to each device library. If found, add to the list // of device libraries that will be linked against. for (const auto &DeviceLib : DeviceLibs) { - bool DeviceLibFound = false; - for (const auto &LibraryPath : LibraryPaths) { - SmallString<128> FullLibName(LibraryPath); - llvm::sys::path::append(FullLibName, DeviceLib.Path); - if (llvm::sys::fs::exists(FullLibName)) { - BitCodeLibraryInfo BitCodeLibrary( - {FullLibName, DeviceLib.ShouldInternalize}); - BCLibs.emplace_back(BitCodeLibrary); - DeviceLibFound = true; - break; - } - } // The device libraries are all known internal libraries. If any are not // found, emit an error. - if (!DeviceLibFound) + if (auto FullLibName = SYCLInstallation.findSYCLDeviceLib(DeviceLib.Path)) + BCLibs.emplace_back( + BitCodeLibraryInfo({*FullLibName, DeviceLib.ShouldInternalize})); + else getDriver().Diag(diag::err_drv_no_sycl_device_lib) << DeviceLib.Path; } return BCLibs; diff --git a/clang/test/Driver/Inputs/SYCL/lib/dpcpp-7/sycl/libsycl-native-bfloat16.bc b/clang/test/Driver/Inputs/SYCL/lib/dpcpp-7/sycl/libsycl-native-bfloat16.bc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/SYCL/lib/dpcpp-7/sycl/libsycl-nativecpu_utils.bc b/clang/test/Driver/Inputs/SYCL/lib/dpcpp-7/sycl/libsycl-nativecpu_utils.bc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/sycl-bc-device-libraries.cpp b/clang/test/Driver/sycl-bc-device-libraries.cpp index 00a8fa628ca5..53f995ddd948 100644 --- a/clang/test/Driver/sycl-bc-device-libraries.cpp +++ b/clang/test/Driver/sycl-bc-device-libraries.cpp @@ -1,13 +1,23 @@ /// Test that SYCL bitcode device libraries are properly separated for NVIDIA and AMD targets. +/// Also test the SYCL device library location passed to clang-linker-wrapper +/// (-sycl-device-library-location) and sycl-post-link (--device-lib-dir). + +/// Check that a device library which cannot be found is diagnosed. +// RUN: not %clang -### -fsycl --offload-new-driver -ccc-install-dir %t.nonexistent/bin \ +// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ +// RUN: -fsycl-targets=nvptx64-nvidia-cuda \ +// RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-NVPTX-MISSING %s +// CHECK-NVPTX-MISSING: cannot find expected SYCL device library 'devicelib-nvptx64-nvidia-cuda.bc' /// Check devicelib are linked for nvptx. -// RUN: %clang -### -fsycl --offload-new-driver \ +// RUN: %clang -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \ // RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda \ // RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \ // RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-NVPTX-BC %s -// RUN: %clang_cl -### -fsycl --offload-new-driver \ +// RUN: %clang_cl -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \ // RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda \ // RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \ @@ -17,14 +27,14 @@ // CHECK-NVPTX-BC-SAME: "--bitcode-library=nvptx64-nvidia-cuda={{.*}}devicelib-nvptx64-nvidia-cuda.bc" /// Check devicelib is linked for amdgcn. -// RUN: %clang -### -fsycl --offload-new-driver \ +// RUN: %clang -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \ // RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ // RUN: -fsycl-targets=amdgcn-amd-amdhsa \ // RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \ // RUN: --rocm-path=%S/Inputs/rocm \ // RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-AMD-BC %s -// RUN: %clang_cl -### -fsycl --offload-new-driver \ +// RUN: %clang_cl -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \ // RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ // RUN: -fsycl-targets=amdgcn-amd-amdhsa \ // RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \ @@ -35,7 +45,7 @@ // CHECK-AMD-BC-SAME: "--bitcode-library=amdgcn-amd-amdhsa={{.*}}devicelib-amdgcn-amd-amdhsa.bc" /// Check linking with multiple targets. -// RUN: %clang -### -fsycl --offload-new-driver \ +// RUN: %clang -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \ // RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ // RUN: -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \ // RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \ @@ -43,7 +53,7 @@ // RUN: --rocm-path=%S/Inputs/rocm \ // RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-MULTI-TARGET %s -// RUN: %clang_cl -### -fsycl --offload-new-driver \ +// RUN: %clang_cl -### -fsycl --offload-new-driver -ccc-install-dir %S/Inputs/SYCL/bin \ // RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ // RUN: -fsycl-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda \ // RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx900 \ @@ -53,3 +63,38 @@ // CHECK-MULTI-TARGET: clang-linker-wrapper // CHECK-MULTI-TARGET-SAME: "--bitcode-library=amdgcn-amd-amdhsa={{.*}}devicelib-amdgcn-amd-amdhsa.bc" "--bitcode-library=nvptx64-nvidia-cuda={{.*}}devicelib-nvptx64-nvidia-cuda.bc" + +/// The device library location is resolved from the library being consumed. +/// Inputs/SYCL matches the Linux install layout, with the libraries in +/// lib/dpcpp-7/sycl. Make sure that location is found, rather than the +/// /../lib fallback. +/// Non-NativeCPU targets use the location of libsycl-native-bfloat16.bc. +// RUN: %clang -### -fsycl --offload-new-driver --target=x86_64-unknown-linux-gnu \ +// RUN: -ccc-install-dir %S/Inputs/SYCL/bin \ +// RUN: -fsycl-targets=spir64 \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-BF16 %s +// CHECK-LIB-LOC-BF16: clang-linker-wrapper{{.*}} "-sycl-device-library-location={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl" + +// RUN: %clang -### -fsycl --no-offload-new-driver --target=x86_64-unknown-linux-gnu \ +// RUN: -ccc-install-dir %S/Inputs/SYCL/bin \ +// RUN: -fsycl-targets=spir64 \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-BF16-POSTLINK %s +// CHECK-LIB-LOC-BF16-POSTLINK: sycl-post-link{{.*}} "--device-lib-dir={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl" + +/// NativeCPU uses the location of libsycl-nativecpu_utils.bc. +// RUN: %clang -### -fsycl --offload-new-driver --target=x86_64-unknown-linux-gnu \ +// RUN: -ccc-install-dir %S/Inputs/SYCL/bin \ +// RUN: -fno-sycl-libspirv -Wno-unsafe-libspirv-not-linked \ +// RUN: -fsycl-targets=native_cpu \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-NATIVECPU %s +// CHECK-LIB-LOC-NATIVECPU: clang-linker-wrapper +// CHECK-LIB-LOC-NATIVECPU-SAME: "--bitcode-library=native_cpu={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl{{[/\\]+}}libsycl-nativecpu_utils.bc" +// CHECK-LIB-LOC-NATIVECPU-SAME: "-sycl-device-library-location={{.*}}SYCL{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}dpcpp-7{{[/\\]+}}sycl" + +/// When the library cannot be found, fall back to /../lib. +// RUN: %clang -### -fsycl --offload-new-driver --target=x86_64-unknown-linux-gnu \ +// RUN: -ccc-install-dir %t.nonexistent/bin \ +// RUN: --no-offloadlib -fno-sycl-instrument-device-code \ +// RUN: -fsycl-targets=spir64 \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-LIB-LOC-FALLBACK %s +// CHECK-LIB-LOC-FALLBACK: clang-linker-wrapper{{.*}} "-sycl-device-library-location={{.*}}.nonexistent{{[/\\]+}}bin{{[/\\]+}}..{{[/\\]+}}lib"