1 cmake_minimum_required(VERSION 3.20.0)
3 if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
4 project(libclc VERSION 0.2.0 LANGUAGES CXX C)
6 set(LLVM_SUBPROJECT_TITLE "libclc")
8 set(CMAKE_CXX_STANDARD 17)
10 # Add path for custom modules
11 list( INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" )
13 set( LIBCLC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
14 set( LIBCLC_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} )
15 set( LIBCLC_OBJFILE_DIR ${LIBCLC_BINARY_DIR}/obj.libclc.dir )
19 include( GNUInstallDirs )
20 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
21 amdgcn-amdhsa/lib/SOURCES;
23 amdgcn-mesa3d/lib/SOURCES;
29 ptx-nvidiacl/lib/SOURCES;
33 # CLC internal libraries
34 clc/lib/generic/SOURCES;
35 clc/lib/clspv/SOURCES;
36 clc/lib/clspv64/SOURCES;
37 clc/lib/spirv/SOURCES;
38 clc/lib/spirv64/SOURCES;
41 set( LIBCLC_MIN_LLVM 3.9.0 )
43 set( LIBCLC_TARGETS_TO_BUILD "all"
44 CACHE STRING "Semicolon-separated list of libclc targets to build, or 'all'." )
46 option( ENABLE_RUNTIME_SUBNORMAL "Enable runtime linking of subnormal support." OFF )
48 if( LIBCLC_STANDALONE_BUILD OR CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
49 # Out-of-tree configuration
50 set( LIBCLC_STANDALONE_BUILD TRUE )
52 find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
55 message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )
57 if( LLVM_PACKAGE_VERSION VERSION_LESS LIBCLC_MIN_LLVM )
58 message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
61 # Import required tools
62 if( NOT EXISTS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} )
63 foreach( tool IN ITEMS clang llvm-as llvm-link opt )
64 find_program( LLVM_TOOL_${tool} ${tool} PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
65 set( ${tool}_exe ${LLVM_TOOL_${tool}} )
70 # In-tree configuration
71 set( LIBCLC_STANDALONE_BUILD FALSE )
73 set( LLVM_PACKAGE_VERSION ${LLVM_VERSION} )
75 # Note that we check this later (for both build types) but we can provide a
76 # more useful error message when built in-tree. We assume that LLVM tools are
77 # always available so don't warn here.
78 if( NOT clang IN_LIST LLVM_ENABLE_PROJECTS )
79 message(FATAL_ERROR "Clang is not enabled, but is required to build libclc in-tree")
82 if( NOT EXISTS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} )
83 get_host_tool_path( clang CLANG clang_exe clang_target )
84 get_host_tool_path( llvm-as LLVM_AS llvm-as_exe llvm-as_target )
85 get_host_tool_path( llvm-link LLVM_LINK llvm-link_exe llvm-link_target )
86 get_host_tool_path( opt OPT opt_exe opt_target )
90 if( EXISTS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} )
91 message( WARNING "Using custom LLVM tools to build libclc: "
92 "${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR}, "
93 " ensure the tools are up to date." )
94 # Note - use a differently named variable than LLVM_TOOL_${tool} as above, as
95 # the variable name is used to cache the result of find_program. If we used
96 # the same name, a user wouldn't be able to switch a build between default
98 foreach( tool IN ITEMS clang llvm-as llvm-link opt )
99 find_program( LLVM_CUSTOM_TOOL_${tool} ${tool}
100 PATHS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
101 set( ${tool}_exe ${LLVM_CUSTOM_TOOL_${tool}} )
102 set( ${tool}_target )
106 foreach( tool IN ITEMS clang opt llvm-as llvm-link )
107 if( NOT EXISTS "${${tool}_exe}" AND "${tool}_target" STREQUAL "" )
108 message( FATAL_ERROR "libclc toolchain incomplete - missing tool ${tool}!" )
112 # llvm-spirv is an optional dependency, used to build spirv-* targets.
113 # It may be provided in-tree or externally.
114 if( TARGET llvm-spirv )
115 get_host_tool_path( llvm-spirv LLVM_SPIRV llvm-spirv_exe llvm-spirv_target )
117 find_program( LLVM_SPIRV llvm-spirv PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
118 set( llvm-spirv_exe "${LLVM_SPIRV}" )
119 set( llvm-spirv_target )
122 # List of all targets. Note that some are added dynamically below.
123 set( LIBCLC_TARGETS_ALL
135 # mesa3d environment is only available since LLVM 4.0
136 if( LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 4.0.0 )
137 list( APPEND LIBCLC_TARGETS_ALL amdgcn-mesa-mesa3d )
140 # spirv-mesa3d and spirv64-mesa3d targets can only be built with the (optional)
141 # llvm-spirv external tool.
143 list( APPEND LIBCLC_TARGETS_ALL spirv-mesa3d- spirv64-mesa3d- )
146 # Verify that the user hasn't requested mesa3d targets without an available
148 if( "spirv-mesa3d-" IN_LIST LIBCLC_TARGETS_TO_BUILD OR "spirv64-mesa3d-" IN_LIST LIBCLC_TARGETS_TO_BUILD )
149 if( NOT llvm-spirv_exe )
150 message( FATAL_ERROR "SPIR-V targets requested, but spirv-tools is not installed" )
154 if( LIBCLC_TARGETS_TO_BUILD STREQUAL "all" )
155 set( LIBCLC_TARGETS_TO_BUILD ${LIBCLC_TARGETS_ALL} )
157 foreach(TARGET_TO_BUILD ${LIBCLC_TARGETS_TO_BUILD})
158 if (NOT ${TARGET_TO_BUILD} IN_LIST LIBCLC_TARGETS_ALL)
159 message ( FATAL_ERROR "Unknown target in LIBCLC_TARGETS_TO_BUILD: \"${TARGET_TO_BUILD}\"\n"
160 "Valid targets are: ${LIBCLC_TARGETS_ALL}\n")
165 list( SORT LIBCLC_TARGETS_TO_BUILD )
167 # Construct LLVM version define
168 set( LLVM_VERSION_DEFINE "-DHAVE_LLVM=0x${LLVM_VERSION_MAJOR}0${LLVM_VERSION_MINOR}" )
170 # This needs to be set before any target that needs it
171 # We need to use LLVM_INCLUDE_DIRS here, because if we are linking to an
172 # llvm build directory, this includes $src/llvm/include which is where all the
173 # headers are not $build/include/ which is what LLVM_INCLUDE_DIR is set to.
174 include_directories( ${LLVM_INCLUDE_DIRS} )
176 # Setup prepare_builtins tools
177 set(LLVM_LINK_COMPONENTS
184 if( LIBCLC_STANDALONE_BUILD )
185 add_llvm_executable( prepare_builtins utils/prepare-builtins.cpp )
186 set( prepare_builtins_exe prepare_builtins )
187 set( prepare_builtins_target prepare_builtins )
189 add_llvm_utility( prepare_builtins utils/prepare-builtins.cpp )
190 setup_host_tool( prepare_builtins PREPARE_BUILTINS prepare_builtins_exe prepare_builtins_target )
192 target_compile_definitions( prepare_builtins PRIVATE ${LLVM_VERSION_DEFINE} )
193 # These were not properly reported in early LLVM and we don't need them
194 target_compile_options( prepare_builtins PRIVATE -fno-rtti -fno-exceptions )
197 set( r600--_devices cedar cypress barts cayman )
198 set( amdgcn--_devices tahiti )
199 set( amdgcn-mesa-mesa3d_devices ${amdgcn--_devices} )
200 set( amdgcn--amdhsa_devices none )
201 set( clspv--_devices none )
202 set( clspv64--_devices none )
203 set( nvptx--_devices none )
204 set( nvptx64--_devices none )
205 set( nvptx--nvidiacl_devices none )
206 set( nvptx64--nvidiacl_devices none )
207 set( spirv-mesa3d-_devices none )
208 set( spirv64-mesa3d-_devices none )
211 set( cedar_aliases palm sumo sumo2 redwood juniper )
212 set( cypress_aliases hemlock )
213 set( barts_aliases turks caicos )
214 set( cayman_aliases aruba )
215 set( tahiti_aliases pitcairn verde oland hainan bonaire kabini kaveri hawaii
216 mullins tonga tongapro iceland carrizo fiji stoney polaris10 polaris11
218 gfx900 gfx902 gfx904 gfx906 gfx908 gfx909 gfx90a gfx90c gfx940 gfx941 gfx942
219 gfx1010 gfx1011 gfx1012 gfx1013
220 gfx1030 gfx1031 gfx1032 gfx1033 gfx1034 gfx1035 gfx1036
221 gfx1100 gfx1101 gfx1102 gfx1103
222 gfx1150 gfx1151 gfx1152 gfx1153
227 configure_file( libclc.pc.in libclc.pc @ONLY )
228 install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libclc.pc DESTINATION "${CMAKE_INSTALL_DATADIR}/pkgconfig" )
229 install( DIRECTORY generic/include/clc DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" )
231 if( ENABLE_RUNTIME_SUBNORMAL )
232 foreach( file IN ITEMS subnormal_use_default subnormal_disable )
235 INPUTS ${CMAKE_CURRENT_SOURCE_DIR}/generic/lib/${file}.ll
238 FILES $<TARGET_PROPERTY:${file},TARGET_FILE>
239 DESTINATION "${CMAKE_INSTALL_DATADIR}/clc"
244 find_package( Python3 REQUIRED COMPONENTS Interpreter )
245 file( TO_CMAKE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/generic/lib/gen_convert.py script_loc )
248 COMMAND ${Python3_EXECUTABLE} ${script_loc} > convert.cl
249 DEPENDS ${script_loc} )
250 add_custom_target( "generate_convert.cl" DEPENDS convert.cl )
251 set_target_properties( "generate_convert.cl" PROPERTIES FOLDER "libclc/Sourcegenning" )
254 OUTPUT clspv-convert.cl
255 COMMAND ${Python3_EXECUTABLE} ${script_loc} --clspv > clspv-convert.cl
256 DEPENDS ${script_loc} )
257 add_custom_target( "clspv-generate_convert.cl" DEPENDS clspv-convert.cl )
258 set_target_properties( "clspv-generate_convert.cl" PROPERTIES FOLDER "libclc/Sourcegenning" )
262 foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
263 message( STATUS "libclc target '${t}' is enabled" )
264 string( REPLACE "-" ";" TRIPLE ${t} )
265 list( GET TRIPLE 0 ARCH )
266 list( GET TRIPLE 1 VENDOR )
267 list( GET TRIPLE 2 OS )
271 if ( NOT ${ARCH} STREQUAL spirv AND NOT ${ARCH} STREQUAL spirv64 AND
272 NOT ${ARCH} STREQUAL clspv AND NOT ${ARCH} STREQUAL clspv64)
273 LIST( APPEND dirs generic )
276 if( ${ARCH} STREQUAL r600 OR ${ARCH} STREQUAL amdgcn )
277 list( APPEND dirs amdgpu )
281 if( ${ARCH} STREQUAL nvptx OR ${ARCH} STREQUAL nvptx64 )
288 libclc_configure_lib_source(
292 DIRS ${dirs} ${DARCH} ${DARCH}-${OS} ${DARCH}-${VENDOR}-${OS}
295 set( opencl_lib_files )
296 set( opencl_gen_files )
298 if( NOT ARCH STREQUAL spirv AND NOT ARCH STREQUAL spirv64 )
299 if( ARCH STREQUAL clspv OR ARCH STREQUAL clspv64 )
300 list( APPEND opencl_gen_files clspv-convert.cl )
301 elseif ( NOT ENABLE_RUNTIME_SUBNORMAL )
302 list( APPEND opencl_gen_files convert.cl )
303 list( APPEND opencl_lib_files generic/lib/subnormal_use_default.ll )
307 libclc_configure_lib_source(
309 DIRS ${dirs} ${DARCH} ${DARCH}-${OS} ${DARCH}-${VENDOR}-${OS}
312 foreach( d ${${t}_devices} )
313 get_libclc_device_info(
317 ARCH_SUFFIX arch_suffix
318 CLANG_TRIPLE clang_triple
321 message( STATUS " device: ${d} ( ${${d}_aliases} )" )
323 if ( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
324 set( build_flags -O0 -finline-hint-functions -DCLC_SPIRV )
326 set( spvflags --spirv-max-version=1.1 )
327 set( MACRO_ARCH SPIRV32 )
328 if( ARCH STREQUAL spirv64 )
329 set( MACRO_ARCH SPIRV64 )
331 elseif( ARCH STREQUAL clspv OR ARCH STREQUAL clspv64 )
332 set( build_flags "-Wno-unknown-assumption" -DCLC_CLSPV )
334 set( MACRO_ARCH CLSPV32 )
335 if( ARCH STREQUAL clspv64 )
336 set( MACRO_ARCH CLSPV64 )
341 set( MACRO_ARCH ${ARCH} )
344 set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" )
345 file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} )
347 string( TOUPPER "CLC_${MACRO_ARCH}" CLC_TARGET_DEFINE )
349 list( APPEND build_flags
351 -D${CLC_TARGET_DEFINE}
352 # All libclc builtin libraries see CLC headers
353 -I${CMAKE_CURRENT_SOURCE_DIR}/clc/include
354 # FIXME: Fix libclc to not require disabling this noisy warning
355 -Wno-bitwise-conditional-parentheses
358 if( NOT "${cpu}" STREQUAL "" )
359 list( APPEND build_flags -mcpu=${cpu} )
362 add_libclc_builtin_set(
365 ARCH_SUFFIX clc-${arch_suffix}
366 TRIPLE ${clang_triple}
367 COMPILE_FLAGS ${build_flags}
368 OPT_FLAGS ${opt_flags}
369 LIB_FILES ${clc_lib_files}
372 list( APPEND build_flags
373 -I${CMAKE_CURRENT_SOURCE_DIR}/generic/include
376 add_libclc_builtin_set(
378 ARCH_SUFFIX ${arch_suffix}
379 TRIPLE ${clang_triple}
380 COMPILE_FLAGS ${build_flags}
381 OPT_FLAGS ${opt_flags}
382 LIB_FILES ${opencl_lib_files}
383 GEN_FILES ${opencl_gen_files}
384 ALIASES ${${d}_aliases}
385 # Link in the CLC builtins and internalize their symbols
386 INTERNAL_LINK_DEPENDENCIES $<TARGET_PROPERTY:builtins.link.clc-${arch_suffix},TARGET_FILE>