[Driver][SYCL] Add compile-time device library linking for SPIR-V targets (#196656) This PR implements compile-time device library linking for SYCL offloading to SPIR-V targets, using `libclang_rt.builtins.bc` - an in-tree compiler-rt artifact produced alongside the existing `libclang_rt.builtins.a` for `SPIRV64`. ## Motivation SYCL device compilations targeting SPIR-V need access to compiler builtins (integer arithmetic, floating-point helpers, etc.) at compile time so the compiler can optimize across user code and builtins, inline aggressively, and eliminate dead code. This PR lays the foundation by wiring up the first in-tree device library : `libclang_rt.builtins.bc` - using the same `-mlink-builtin-bitcode` mechanism already used by `libclc` and `HIP`. ## Changes **compiler-rt (compiler-rt/lib/builtins/CMakeLists.txt)** For the `spirv64` target, after building `libclang_rt.builtins-spirv64.a`, runs `llvm-link` to merge all bitcode objects into a single `libclang_rt.builtins.bc`. This file is installed to `<ResourceDir>/lib/spirv64-unknown-unknown/` alongside the static archive. The `-mlink-builtin-bitcode` flag requires raw LLVM IR and cannot unpack a static archive directly, hence the extra step. **Clang Driver (clang/lib/Driver/ToolChains/SYCL.cpp)** `SYCLToolChain::getDeviceLibs()` now constructs the path to `libclang_rt.builtins.bc` under the clang resource directory and returns it for `-mlink-builtin-bitcode` injection during `spirv64` device compilation. If the file is absent (e.g. compiler-rt was not built with spirv64 support), a specific diagnostic is emitted. Linking is suppressed when `--no-offloadlib` is passed. **Diagnostics (clang/include/clang/Basic/DiagnosticDriverKinds.td)** Added `err_drv_no_compiler_rt_builtins_bc`, following the `err_drv_libclc_not_found` community pattern, with actionable guidance on how to build compiler-rt with SPIR-V support. ### Test Infrastructure 1. `clang/test/Driver/sycl-device-lib-spirv64.cpp` - new test verifying -mlink-builtin-bitcode is passed for spirv64, suppressed with --no-offloadlib, and that a missing .bc produces the correct diagnostic. 2. `clang/test/Driver/Inputs/spirv64-sycl/` - dummy resource-dir fixture used by driver tests. 3. All existing SYCL driver tests updated to pass -`resource-dir %S/Inputs/spirv64-sycl `on -fsycl RUN lines, making them independent of the installed clang resource directory on CI runners. ## Behavior ### Default ```bash clang -fsycl myprogram.cpp # Device compilation includes: # "-mlink-builtin-bitcode" "<ResourceDir>/lib/spirv64-unknown-unknown/libclang_rt.builtins.bc" ``` Automatically links device libraries from `<clang-install>/lib/` during device compilation. ### Without device libraries ```bash clang -fsycl --no-offloadlib myprogram.cpp # -mlink-builtin-bitcode is suppressed ``` Missing .bc (compiler-rt not built with spirv64 support) ```bash error: no compiler-rt builtins bitcode library '...' found in the clang resource directory; build compiler-rt with SPIR-V support or pass '--no-offloadlib' to compile without it ``` GitOrigin-RevId: 5a650306e4e1069d194d8fcfeee821d7e424f9b3
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index ea21c36..8761e25 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt
@@ -1147,6 +1147,38 @@ get_compiler_rt_output_dir(${arch} BUILTIN_LIB_OUTPUT_DIR) set_output_name(BUILTIN_LIB_OUTPUT_NAME clang_rt.builtins ${arch}) file(WRITE "${BUILTIN_LIB_OUTPUT_DIR}/${BUILTIN_LIB_OUTPUT_NAME}.sources.txt" "${${arch}_SOURCES}") + + # For spirv64, produce a combined bitcode file alongside the static archive. + # -mlink-builtin-bitcode expects raw LLVM IR and cannot unpack a static archive, + # so we use llvm-link to merge the archive members into a single .bc file. + if("${arch}" MATCHES "^spirv64") + find_program(LLVM_LINK llvm-link + PATHS ${LLVM_TOOLS_BINARY_DIR} + NO_DEFAULT_PATH) + if(LLVM_LINK) + set(SPIRV64_BC_OUTPUT "${BUILTIN_LIB_OUTPUT_DIR}/lib${BUILTIN_LIB_OUTPUT_NAME}.bc") + add_custom_command( + OUTPUT "${SPIRV64_BC_OUTPUT}" + COMMAND "${LLVM_LINK}" + "$<TARGET_FILE:clang_rt.builtins-spirv64>" + -o "${SPIRV64_BC_OUTPUT}" + DEPENDS clang_rt.builtins-${arch} + COMMENT "Linking lib${BUILTIN_LIB_OUTPUT_NAME}.bc" + VERBATIM) + add_custom_target(clang_rt.builtins-spirv64-bc ALL + DEPENDS "${SPIRV64_BC_OUTPUT}") + add_dependencies(builtins clang_rt.builtins-spirv64-bc) + get_compiler_rt_install_dir(${arch} BUILTIN_INSTALL_DIR) + install(FILES "${SPIRV64_BC_OUTPUT}" + DESTINATION "${BUILTIN_INSTALL_DIR}" + COMPONENT builtins) + else() + message(WARNING + "llvm-link not found (LLVM_TOOLS_BINARY_DIR='${LLVM_TOOLS_BINARY_DIR}'); " + "skipping libclang_rt.builtins.bc for spirv64") + endif() + endif() + cmake_pop_check_state() endif () endforeach ()