-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[clang] Add the ability to link libclc OpenCL libraries #146503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-testing-tools @llvm/pr-subscribers-clang Author: Fraser Cormack (frasercrmck) ChangesThis commit adds driver support for linking libclc OpenCL libraries. It Not all libclc targets have corresponding clang targets. For this reason To accommodate this option, libclc libraries are now placed into clang's Currently only the AMDGPU toolchain supports this option as a proof of Full diff: https://github.com/llvm/llvm-project/pull/146503.diff 10 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 68f87ebb1b39f..93f78d4050621 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -392,6 +392,9 @@ def warn_drv_fraw_string_literals_in_cxx11 : Warning<
"ignoring '-f%select{no-|}0raw-string-literals', which is only valid for C and C++ standards before C++11">,
InGroup<UnusedCommandLineArgument>;
+def err_drv_libclc_not_found : Error<
+ "no libclc library '%0' found in the clang resource directory or in LIBRARY_PATH">;
+
def err_drv_invalid_malign_branch_EQ : Error<
"invalid argument '%0' to -malign-branch=; each element must be one of: %1">;
diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index ddb21c1e8a8b8..e4df510b91c78 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -213,6 +213,9 @@ void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
StringRef BitcodeSuffix, const llvm::Triple &Triple,
const ToolChain &HostTC);
+void addOpenCLBuiltinsLib(const Driver &D, const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args);
+
void addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 0822df2640d23..6d019ecc26c68 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1421,6 +1421,8 @@ def openacc_macro_override_EQ
// End Clang specific/exclusive options for OpenACC.
+def libclc_lib_EQ : Joined<["--"], "libclc-lib=">, Group<opencl_Group>,
+ HelpText<"Namespec of libclc OpenCL bitcode library to link">;
def libomptarget_amdgpu_bc_path_EQ : Joined<["--"], "libomptarget-amdgpu-bc-path=">, Group<i_Group>,
HelpText<"Path to libomptarget-amdgcn bitcode library">;
def libomptarget_amdgcn_bc_path_EQ : Joined<["--"], "libomptarget-amdgcn-bc-path=">, Group<i_Group>,
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index b7564a0495da8..e6d1baa2a1caa 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -795,6 +795,8 @@ void AMDGPUToolChain::addClangTargetOptions(
CC1Args.push_back("-fvisibility=hidden");
CC1Args.push_back("-fapply-global-visibility-to-externs");
}
+
+ addOpenCLBuiltinsLib(getDriver(), DriverArgs, CC1Args);
}
void AMDGPUToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 672b73432847d..650881e21fb77 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -2870,6 +2870,65 @@ void tools::addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C,
}
}
+void tools::addOpenCLBuiltinsLib(const Driver &D,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) {
+ // Check whether user specifies a libclc bytecode library
+ if (const Arg *A = DriverArgs.getLastArg(options::OPT_libclc_lib_EQ)) {
+ SmallVector<StringRef, 8> LibraryPaths;
+
+ // Add user defined library paths from LIBRARY_PATH.
+ std::optional<std::string> LibPath =
+ llvm::sys::Process::GetEnv("LIBRARY_PATH");
+ if (LibPath) {
+ SmallVector<StringRef, 8> Frags;
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
+ llvm::SplitString(*LibPath, Frags, EnvPathSeparatorStr);
+ for (StringRef Path : Frags)
+ LibraryPaths.emplace_back(Path.trim());
+ }
+
+ // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/libclc/
+ SmallString<128> LibclcPath(D.ResourceDir);
+ llvm::sys::path::append(LibclcPath, "lib", "libclc");
+ LibraryPaths.emplace_back(LibclcPath);
+
+ bool FoundBCLibrary = false;
+ StringRef LibclcNamespec(A->getValue());
+
+ // If the namespec is of the form :filename, search for that file.
+ bool FilenameSearch = LibclcNamespec.starts_with(":");
+ SmallString<128> LibclcTargetFile(
+ LibclcNamespec.drop_front(FilenameSearch ? 1 : 0));
+
+ if (FilenameSearch && llvm::sys::fs::exists(LibclcTargetFile)) {
+ FoundBCLibrary = true;
+ CC1Args.push_back("-mlink-builtin-bitcode");
+ CC1Args.push_back(DriverArgs.MakeArgString(LibclcTargetFile));
+ } else {
+ // Search the library paths for the file
+ if (!FilenameSearch)
+ LibclcTargetFile += ".bc";
+
+ for (StringRef LibraryPath : LibraryPaths) {
+ SmallString<128> LibclcPath(LibraryPath);
+ llvm::sys::path::append(LibclcPath, LibclcTargetFile);
+ if (llvm::sys::fs::exists(LibclcPath)) {
+ FoundBCLibrary = true;
+ CC1Args.push_back("-mlink-builtin-bitcode");
+ CC1Args.push_back(DriverArgs.MakeArgString(LibclcPath));
+ break;
+ }
+ }
+ }
+
+ // Since the user requested a library, if we haven't one then report an
+ // error.
+ if (!FoundBCLibrary)
+ D.Diag(diag::err_drv_libclc_not_found) << LibclcTargetFile;
+ }
+}
+
void tools::addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
diff --git a/clang/test/Driver/Inputs/libclc/libclc.bc b/clang/test/Driver/Inputs/libclc/libclc.bc
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang/test/Driver/Inputs/libclc/subdir/libclc.bc b/clang/test/Driver/Inputs/libclc/subdir/libclc.bc
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang/test/Driver/opencl-libclc.cl b/clang/test/Driver/opencl-libclc.cl
new file mode 100644
index 0000000000000..34b863b128682
--- /dev/null
+++ b/clang/test/Driver/opencl-libclc.cl
@@ -0,0 +1,10 @@
+// RUN: %clang -### -target amdgcn-amd-amdhsa --no-offloadlib --libclc-lib=:%S/Inputs/libclc/libclc.bc %s 2>&1 | FileCheck %s
+// RUN: env LIBRARY_PATH=%S/Inputs/libclc:$LIBRARY_PATH %clang -### -target amdgcn-amd-amdhsa --no-offloadlib --libclc-lib=libclc %s 2>&1 | FileCheck %s
+// RUN: env LIBRARY_PATH=%S/Inputs/libclc:$LIBRARY_PATH %clang -### -target amdgcn-amd-amdhsa --no-offloadlib --libclc-lib=:libclc.bc %s 2>&1 | FileCheck %s
+
+// RUN: env LIBRARY_PATH=%S/Inputs/libclc/subdir:$LIBRARY_PATH %clang -### -target amdgcn-amd-amdhsa --no-offloadlib --libclc-lib=libclc %s 2>&1 | FileCheck %s --check-prefix CHECK-SUBDIR
+// RUN: env LIBRARY_PATH=%S/Inputs/libclc/subdir:$LIBRARY_PATH %clang -### -target amdgcn-amd-amdhsa --no-offloadlib --libclc-lib=:libclc.bc %s 2>&1 | FileCheck %s --check-prefix CHECK-SUBDIR
+// RUN: env LIBRARY_PATH=%S/Inputs/libclc:$LIBRARY_PATH %clang -### -target amdgcn-amd-amdhsa --no-offloadlib --libclc-lib=:subdir/libclc.bc %s 2>&1 | FileCheck %s --check-prefix CHECK-SUBDIR
+
+// CHECK: -mlink-builtin-bitcode{{.*}}Inputs/libclc/libclc.bc
+// CHECK-SUBDIR: -mlink-builtin-bitcode{{.*}}Inputs/libclc/subdir/libclc.bc
diff --git a/libclc/CMakeLists.txt b/libclc/CMakeLists.txt
index c98e2043464d9..c8d38ceadcca1 100644
--- a/libclc/CMakeLists.txt
+++ b/libclc/CMakeLists.txt
@@ -63,6 +63,10 @@ if( LIBCLC_STANDALONE_BUILD OR CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DI
set( ${tool}_target )
endforeach()
endif()
+
+ # Setup the paths where libclc runtimes should be stored.
+ set( LIBCLC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} )
+ set( LIBCLC_OUTPUT_LIBRARY_DIR ${LIBCLC_OUTPUT_DIR} )
else()
# In-tree configuration
set( LIBCLC_STANDALONE_BUILD FALSE )
@@ -82,6 +86,13 @@ else()
get_host_tool_path( llvm-link LLVM_LINK llvm-link_exe llvm-link_target )
get_host_tool_path( opt OPT opt_exe opt_target )
endif()
+
+ # Setup the paths where libclc runtimes should be stored. By default, in an
+ # in-tree build we place the libraries in clang's resource driectory.
+ get_clang_resource_dir( LIBCLC_OUTPUT_DIR PREFIX ${LLVM_LIBRARY_OUTPUT_INTDIR}/.. )
+
+ # Note we do not adhere to LLVM_ENABLE_PER_TARGET_RUNTIME_DIR.
+ set( LIBCLC_OUTPUT_LIBRARY_DIR ${LIBCLC_OUTPUT_DIR}/lib/libclc )
endif()
if( EXISTS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} )
diff --git a/libclc/cmake/modules/AddLibclc.cmake b/libclc/cmake/modules/AddLibclc.cmake
index 597bb642655e4..2483e3d86a4ad 100644
--- a/libclc/cmake/modules/AddLibclc.cmake
+++ b/libclc/cmake/modules/AddLibclc.cmake
@@ -120,14 +120,14 @@ function(link_bc)
endif()
add_custom_command(
- OUTPUT ${ARG_TARGET}.bc
- COMMAND ${llvm-link_exe} ${link_flags} -o ${ARG_TARGET}.bc ${LINK_INPUT_ARG}
+ OUTPUT ${LIBCLC_ARCH_OBJFILE_DIR}/${ARG_TARGET}.bc
+ COMMAND ${llvm-link_exe} ${link_flags} -o ${LIBCLC_ARCH_OBJFILE_DIR}/${ARG_TARGET}.bc ${LINK_INPUT_ARG}
DEPENDS ${llvm-link_target} ${ARG_DEPENDENCIES} ${ARG_INPUTS} ${RSP_FILE}
)
- add_custom_target( ${ARG_TARGET} ALL DEPENDS ${ARG_TARGET}.bc )
+ add_custom_target( ${ARG_TARGET} ALL DEPENDS ${LIBCLC_ARCH_OBJFILE_DIR}/${ARG_TARGET}.bc )
set_target_properties( ${ARG_TARGET} PROPERTIES
- TARGET_FILE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}.bc
+ TARGET_FILE ${LIBCLC_ARCH_OBJFILE_DIR}/${ARG_TARGET}.bc
FOLDER "libclc/Device IR/Linking"
)
endfunction()
@@ -358,14 +358,15 @@ function(add_libclc_builtin_set)
if( ARG_ARCH STREQUAL spirv OR ARG_ARCH STREQUAL spirv64 )
set( spv_suffix ${ARG_ARCH_SUFFIX}.spv )
- add_custom_command( OUTPUT ${spv_suffix}
- COMMAND ${llvm-spirv_exe} ${spvflags} -o ${spv_suffix} ${builtins_link_lib}
+ add_custom_command( OUTPUT ${LIBCLC_OUTPUT_LIBRARY_DIR}/${spv_suffix}
+ COMMAND ${llvm-spirv_exe} ${spvflags} -o ${LIBCLC_OUTPUT_LIBRARY_DIR}/${spv_suffix} ${builtins_link_lib}
DEPENDS ${llvm-spirv_target} ${builtins_link_lib} ${builtins_link_lib_tgt}
)
- add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" )
+ add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${LIBCLC_OUTPUT_LIBRARY_DIR}/${spv_suffix}" )
set_target_properties( "prepare-${spv_suffix}" PROPERTIES FOLDER "libclc/Device IR/Prepare" )
- install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix}
- DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
+ install( FILES ${LIBCLC_OUTPUT_LIBRARY_DIR}/${spv_suffix}
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clc"
+ )
return()
endif()
@@ -373,16 +374,16 @@ function(add_libclc_builtin_set)
set( builtins_opt_lib_tgt builtins.opt.${ARG_ARCH_SUFFIX} )
# Add opt target
- add_custom_command( OUTPUT ${builtins_opt_lib_tgt}.bc
- COMMAND ${opt_exe} ${ARG_OPT_FLAGS} -o ${builtins_opt_lib_tgt}.bc
+ add_custom_command( OUTPUT ${LIBCLC_ARCH_OBJFILE_DIR}/${builtins_opt_lib_tgt}.bc
+ COMMAND ${opt_exe} ${ARG_OPT_FLAGS} -o ${LIBCLC_ARCH_OBJFILE_DIR}/${builtins_opt_lib_tgt}.bc
${builtins_link_lib}
DEPENDS ${opt_target} ${builtins_link_lib} ${builtins_link_lib_tgt}
)
add_custom_target( ${builtins_opt_lib_tgt}
- ALL DEPENDS ${builtins_opt_lib_tgt}.bc
+ ALL DEPENDS ${LIBCLC_ARCH_OBJFILE_DIR}/${builtins_opt_lib_tgt}.bc
)
set_target_properties( ${builtins_opt_lib_tgt} PROPERTIES
- TARGET_FILE ${CMAKE_CURRENT_BINARY_DIR}/${builtins_opt_lib_tgt}.bc
+ TARGET_FILE ${LIBCLC_ARCH_OBJFILE_DIR}/${builtins_opt_lib_tgt}.bc
FOLDER "libclc/Device IR/Opt"
)
@@ -390,26 +391,32 @@ function(add_libclc_builtin_set)
# Add prepare target
set( obj_suffix ${ARG_ARCH_SUFFIX}.bc )
- add_custom_command( OUTPUT ${obj_suffix}
- COMMAND ${prepare_builtins_exe} -o ${obj_suffix} ${builtins_opt_lib}
- DEPENDS ${builtins_opt_lib} ${builtins_opt_lib_tgt} ${prepare_builtins_target} )
- add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${obj_suffix} )
- set_target_properties( "prepare-${obj_suffix}" PROPERTIES FOLDER "libclc/Device IR/Prepare" )
+ set( libclc_bc_lib ${LIBCLC_OUTPUT_LIBRARY_DIR}/${obj_suffix} )
+ add_custom_command( OUTPUT ${libclc_bc_lib}
+ COMMAND ${prepare_builtins_exe} -o ${libclc_bc_lib} ${builtins_opt_lib}
+ DEPENDS ${builtins_opt_lib} ${builtins_opt_lib_tgt} ${prepare_builtins_target}
+ WORKING_DIRECTORY ${LIBCLC_OUTPUT_LIBRARY_DIR}
+ )
+ add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${libclc_bc_lib} )
+ set_target_properties( "prepare-${obj_suffix}" PROPERTIES
+ TARGET_FILE ${libclc_bc_lib}
+ FOLDER "libclc/Device IR/Prepare"
+ )
# nvptx-- targets don't include workitem builtins, and clspv targets don't
# include all OpenCL builtins
if( NOT ARG_ARCH MATCHES "^(nvptx|clspv)(64)?$" )
add_test( NAME external-calls-${obj_suffix}
- COMMAND ./check_external_calls.sh ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} ${LLVM_TOOLS_BINARY_DIR}
+ COMMAND ./check_external_calls.sh ${libclc_bc_lib} ${LLVM_TOOLS_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
endif()
- install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
+ install( FILES ${libclc_bc_lib} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
foreach( a ${ARG_ALIASES} )
set( alias_suffix "${a}-${ARG_TRIPLE}.bc" )
add_custom_command(
OUTPUT ${alias_suffix}
- COMMAND ${CMAKE_COMMAND} -E create_symlink ${obj_suffix} ${alias_suffix}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink ${libclc_bc_lib} ${alias_suffix}
DEPENDS prepare-${obj_suffix} )
add_custom_target( alias-${alias_suffix} ALL DEPENDS ${alias_suffix} )
set_target_properties( alias-${alias_suffix} PROPERTIES FOLDER "libclc/Device IR/Aliases" )
|
This commit adds driver support for linking libclc OpenCL libraries. It takes the form of a new optional flag: --libclc-lib=namespec. Nothing is linked unless this flag is specified. Not all libclc targets have corresponding clang targets. For this reason it is desirable for users to be able to specify a libclc library name. We support this by taking both a library name (without the .bc suffix) or a filename. Both of these are searched for in the clang resource directory or in the LIBRARY_PATH environment variable. Filenames are also checked themselves so that absolute paths can be provided. The syntax for specifying filenames (as opposed to library names) uses a leading colon (:), inspired by the -l option. To accommodate this option, libclc libraries are now placed into clang's resource directory in an in-tree configuration. The aliases are not currently placed there to avoid polluting the directory, but that can be changed. The libraries are all placed in <resource-dir>/lib/libclc and are not grouped under host-specific directories as some other runtime libraries are; it is not expected that OpenCL libraries will differ depending on the host toolchain. Currently only the AMDGPU toolchain supports this option as a proof of concept. Other targets such as NVPTX or SPIR/SPIR-V could support it too. We could optionally let target toolchains search for libclc libraries themselves, possibly when passed an empty --libclc-lib.
67a0edc
to
d42bc97
Compare
Windows failures appear to be #145703 |
0004c8f
to
d42bc97
Compare
This commit adds driver support for linking libclc OpenCL libraries. It
takes the form of a new optional flag: --libclc-lib=namespec. Nothing is
linked unless this flag is specified.
Not all libclc targets have corresponding clang targets. For this reason
it is desirable for users to be able to specify a libclc library name.
We support this by taking both a library name (without the .bc suffix)
or a filename. Both of these are searched for in the clang resource
directory or in the LIBRARY_PATH environment variable. Filenames are
also checked themselves so that absolute paths can be provided. The
syntax for specifying filenames (as opposed to library names) uses a
leading colon (:), inspired by the -l option.
To accommodate this option, libclc libraries are now placed into clang's
resource directory in an in-tree configuration. The aliases are not
currently placed there to avoid polluting the directory, but that can be
changed. The libraries are all placed in /lib/libclc and
are not grouped under host-specific directories as some other runtime
libraries are; it is not expected that OpenCL libraries will differ
depending on the host toolchain.
Currently only the AMDGPU toolchain supports this option as a proof of
concept. Other targets such as NVPTX or SPIR/SPIR-V could support it
too. We could optionally let target toolchains search for libclc
libraries themselves, possibly when passed an empty --libclc-lib.