Skip to content

Commit 47cd6dd

Browse files
committed
[libclc] Refactor build system to allow in-tree builds
The previous build system was adding custom "OpenCL" and "LLVM IR" languages in CMake to build the builtin libraries. This was making it harder to build in-tree because the tool binaries needed to be present at configure time. This commit refactors the build system to use custom commands to build the bytecode files one by one, and link them all together into the final bytecode library. It also enables in-tree builds by aliasing the clang/llvm-link/etc. tool targets to internal targets, which are imported from the LLVM installation directory when building out of tree. Diffing (with llvm-diff) all of the final bytecode libraries in an out-of-tree configuration against those built using the current tip system shows no changes. Note that there are textual changes to metadata IDs which confuse regular diff, and that llvm-diff 14 and below may show false-positives. This commit also removes a file listed in one of the SOURCEs which didn't exist and which was preventing the use of ENABLE_RUNTIME_SUBNORMAL when configuring CMake.
1 parent 9391ff8 commit 47cd6dd

12 files changed

+305
-306
lines changed

libclc/CMakeLists.txt

Lines changed: 149 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ project( libclc VERSION 0.2.0 LANGUAGES CXX C)
44

55
set(CMAKE_CXX_STANDARD 17)
66

7+
# Add path for custom modules
8+
list( INSERT CMAKE_MODULE_PATH 0 "${PROJECT_SOURCE_DIR}/cmake/modules" )
9+
10+
set( LIBCLC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
11+
set( LIBCLC_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} )
12+
set( LIBCLC_OBJFILE_DIR ${LIBCLC_BINARY_DIR}/obj.libclc.dir )
13+
14+
include( AddLibclc )
15+
716
include( GNUInstallDirs )
817
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
918
amdgcn-amdhsa/lib/SOURCES;
@@ -27,31 +36,51 @@ set( LIBCLC_TARGETS_TO_BUILD "all"
2736

2837
option( ENABLE_RUNTIME_SUBNORMAL "Enable runtime linking of subnormal support." OFF )
2938

30-
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
31-
include(AddLLVM)
39+
if( LIBCLC_STANDALONE_BUILD OR CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
40+
# Out-of-tree configuration
41+
set( LIBCLC_STANDALONE_BUILD TRUE )
3242

33-
message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )
43+
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
44+
include(AddLLVM)
3445

35-
if( LLVM_PACKAGE_VERSION VERSION_LESS LIBCLC_MIN_LLVM )
36-
message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
37-
endif()
46+
message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )
3847

39-
find_program( LLVM_CLANG clang PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
40-
find_program( LLVM_AS llvm-as PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
41-
find_program( LLVM_LINK llvm-link PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
42-
find_program( LLVM_OPT opt PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
43-
find_program( LLVM_SPIRV llvm-spirv PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
48+
if( LLVM_PACKAGE_VERSION VERSION_LESS LIBCLC_MIN_LLVM )
49+
message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
50+
endif()
4451

45-
# Print toolchain
46-
message( STATUS "libclc toolchain - clang: ${LLVM_CLANG}" )
47-
message( STATUS "libclc toolchain - llvm-as: ${LLVM_AS}" )
48-
message( STATUS "libclc toolchain - llvm-link: ${LLVM_LINK}" )
49-
message( STATUS "libclc toolchain - opt: ${LLVM_OPT}" )
50-
message( STATUS "libclc toolchain - llvm-spirv: ${LLVM_SPIRV}" )
51-
if( NOT LLVM_CLANG OR NOT LLVM_OPT OR NOT LLVM_AS OR NOT LLVM_LINK )
52+
# Import required tools as targets
53+
foreach( tool clang llvm-as llvm-link opt )
54+
find_program( LLVM_TOOL_${tool} ${tool} PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
55+
add_executable( libclc::${tool} IMPORTED GLOBAL )
56+
set_target_properties( libclc::${tool} PROPERTIES IMPORTED_LOCATION ${LLVM_TOOL_${tool}} )
57+
endforeach()
58+
else()
59+
# In-tree configuration
60+
set( LIBCLC_STANDALONE_BUILD FALSE )
61+
62+
set( LLVM_PACKAGE_VERSION ${LLVM_VERSION} )
63+
64+
# Note that we check this later (for both build types) but we can provide a
65+
# more useful error message when built in-tree. We assume that LLVM tools are
66+
# always available so don't warn here.
67+
if( NOT clang IN_LIST LLVM_ENABLE_PROJECTS )
68+
message(FATAL_ERROR "Clang is not enabled, but is required to build libclc in-tree")
69+
endif()
70+
71+
foreach( tool clang llvm-as llvm-link opt )
72+
add_executable(libclc::${tool} ALIAS ${tool})
73+
endforeach()
74+
endif()
75+
76+
if( NOT TARGET libclc::clang OR NOT TARGET libclc::opt
77+
OR NOT TARGET libclc::llvm-as OR NOT TARGET libclc::llvm-link )
5278
message( FATAL_ERROR "libclc toolchain incomplete!" )
5379
endif()
5480

81+
# llvm-spirv is an optional dependency, used to build spirv-* targets.
82+
find_program( LLVM_SPIRV llvm-spirv PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
83+
5584
# List of all targets. Note that some are added dynamically below.
5685
set( LIBCLC_TARGETS_ALL
5786
amdgcn--
@@ -90,24 +119,9 @@ if( "spirv-mesa3d-" IN_LIST LIBCLC_TARGETS_TO_BUILD OR "spirv64-mesa3d-" IN_LIST
90119
endif()
91120
endif()
92121

93-
set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake )
94-
set( CMAKE_CLC_COMPILER ${LLVM_CLANG} )
95-
set( CMAKE_CLC_ARCHIVE ${LLVM_LINK} )
96-
set( CMAKE_LLAsm_PREPROCESSOR ${LLVM_CLANG} )
97-
set( CMAKE_LLAsm_COMPILER ${LLVM_AS} )
98-
set( CMAKE_LLAsm_ARCHIVE ${LLVM_LINK} )
99-
100122
# Construct LLVM version define
101123
set( LLVM_VERSION_DEFINE "-DHAVE_LLVM=0x${LLVM_VERSION_MAJOR}0${LLVM_VERSION_MINOR}" )
102124

103-
104-
# LLVM 13 enables standard includes by default
105-
if( LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 13.0.0 )
106-
set( CMAKE_LLAsm_FLAGS "${CMAKE_LLAsm_FLAGS} -cl-no-stdinc" )
107-
set( CMAKE_CLC_FLAGS "${CMAKE_CLC_FLAGS} -cl-no-stdinc" )
108-
endif()
109-
110-
enable_language( CLC LLAsm )
111125
# This needs to be set before any target that needs it
112126
# We need to use LLVM_INCLUDE_DIRS here, because if we are linking to an
113127
# llvm build directory, this includes $src/llvm/include which is where all the
@@ -122,7 +136,7 @@ set(LLVM_LINK_COMPONENTS
122136
IRReader
123137
Support
124138
)
125-
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
139+
if( LIBCLC_STANDALONE_BUILD )
126140
add_llvm_executable( prepare_builtins utils/prepare-builtins.cpp )
127141
else()
128142
add_llvm_utility( prepare_builtins utils/prepare-builtins.cpp )
@@ -167,12 +181,15 @@ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libclc.pc DESTINATION "${CMAKE_INSTAL
167181
install( DIRECTORY generic/include/clc DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" )
168182

169183
if( ENABLE_RUNTIME_SUBNORMAL )
170-
add_library( subnormal_use_default STATIC
171-
generic/lib/subnormal_use_default.ll )
172-
add_library( subnormal_disable STATIC
173-
generic/lib/subnormal_disable.ll )
174-
install( TARGETS subnormal_use_default subnormal_disable ARCHIVE
175-
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
184+
foreach( file subnormal_use_default subnormal_disable )
185+
link_bc(
186+
OUTPUT ${LIBCLC_OBJFILE_DIR}/${file}.bc
187+
INPUTS ${PROJECT_SOURCE_DIR}/generic/lib/${file}.ll
188+
)
189+
add_custom_target( ${file}.bc ALL DEPENDS ${LIBCLC_OBJFILE_DIR}/${file}.bc )
190+
install( FILES ${LIBCLC_OBJFILE_DIR}/${file}.bc ARCHIVE
191+
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
192+
endforeach()
176193
endif()
177194

178195
find_package( Python3 REQUIRED COMPONENTS Interpreter )
@@ -232,128 +249,152 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
232249

233250
# Add the generated convert.cl here to prevent adding the one listed in
234251
# SOURCES
252+
set( objects ) # A "set" of already-added input files
253+
set( rel_files ) # Source directory input files, relative to the root dir
254+
set( gen_files ) # Generated binary input files, relative to the binary dir
235255
if( NOT ${ARCH} STREQUAL "spirv" AND NOT ${ARCH} STREQUAL "spirv64" )
236256
if( NOT ENABLE_RUNTIME_SUBNORMAL AND NOT ${ARCH} STREQUAL "clspv" AND
237257
NOT ${ARCH} STREQUAL "clspv64" )
238-
set( rel_files convert.cl )
239-
set( objects convert.cl )
258+
list( APPEND gen_files convert.cl )
259+
list( APPEND objects convert.cl )
240260
list( APPEND rel_files generic/lib/subnormal_use_default.ll )
241261
elseif(${ARCH} STREQUAL "clspv" OR ${ARCH} STREQUAL "clspv64")
242-
set( rel_files clspv-convert.cl )
243-
set( objects clspv-convert.cl )
262+
list( APPEND gen_files clspv-convert.cl )
263+
list( APPEND objects clspv-convert.cl )
244264
endif()
245-
else()
246-
set( rel_files )
247-
set( objects )
248265
endif()
249266

250267
foreach( l ${source_list} )
251268
file( READ ${l} file_list )
252269
string( REPLACE "\n" ";" file_list ${file_list} )
253270
get_filename_component( dir ${l} DIRECTORY )
254271
foreach( f ${file_list} )
255-
list( FIND objects ${f} found )
256-
if( found EQUAL -1 )
272+
# Only add each file once, so that targets can 'specialize' builtins
273+
if( NOT ${f} IN_LIST objects )
257274
list( APPEND objects ${f} )
258275
list( APPEND rel_files ${dir}/${f} )
259-
# FIXME: This should really go away
260-
file( TO_CMAKE_PATH ${PROJECT_SOURCE_DIR}/${dir}/${f} src_loc )
261-
get_filename_component( fdir ${src_loc} DIRECTORY )
262-
263-
set_source_files_properties( ${dir}/${f}
264-
PROPERTIES COMPILE_FLAGS "-I ${fdir}" )
265276
endif()
266277
endforeach()
267278
endforeach()
268279

269280
foreach( d ${${t}_devices} )
270-
# Some targets don't have a specific GPU to target
271-
if( ${d} STREQUAL "none" OR ${ARCH} STREQUAL "spirv" OR ${ARCH} STREQUAL "spirv64" )
272-
set( mcpu )
273-
set( arch_suffix "${t}" )
274-
else()
275-
set( mcpu "-mcpu=${d}" )
276-
set( arch_suffix "${d}-${t}" )
281+
get_libclc_device_info(
282+
TRIPLE ${t}
283+
DEVICE ${d}
284+
CPU cpu
285+
ARCH_SUFFIX arch_suffix
286+
CLANG_TRIPLE clang_triple
287+
)
288+
289+
set( mcpu )
290+
if( NOT "${cpu}" STREQUAL "" )
291+
set( mcpu "-mcpu=${cpu}" )
277292
endif()
293+
278294
message( STATUS " device: ${d} ( ${${d}_aliases} )" )
279295

280-
if ( ${ARCH} STREQUAL "spirv" OR ${ARCH} STREQUAL "spirv64" )
281-
if( ${ARCH} STREQUAL "spirv" )
282-
set( t "spir--" )
283-
else()
284-
set( t "spir64--" )
285-
endif()
296+
if ( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
286297
set( build_flags -O0 -finline-hint-functions )
287298
set( opt_flags )
288299
set( spvflags --spirv-max-version=1.1 )
289-
elseif( ${ARCH} STREQUAL "clspv" )
290-
set( t "spir--" )
291-
set( build_flags "-Wno-unknown-assumption")
292-
set( opt_flags -O3 )
293-
elseif( ${ARCH} STREQUAL "clspv64" )
294-
set( t "spir64--" )
300+
elseif( ARCH STREQUAL clspv OR ARCH STREQUAL clspv64 )
295301
set( build_flags "-Wno-unknown-assumption")
296302
set( opt_flags -O3 )
297303
else()
298304
set( build_flags )
299305
set( opt_flags -O3 )
300306
endif()
301307

302-
set( builtins_link_lib_tgt builtins.link.${arch_suffix} )
303-
add_library( ${builtins_link_lib_tgt} STATIC ${rel_files} )
304-
# Make sure we depend on the pseudo target to prevent
305-
# multiple invocations
306-
add_dependencies( ${builtins_link_lib_tgt} generate_convert.cl )
307-
add_dependencies( ${builtins_link_lib_tgt} clspv-generate_convert.cl )
308-
# CMake will turn this include into absolute path
309-
target_include_directories( ${builtins_link_lib_tgt} PRIVATE
310-
"generic/include" )
311-
target_compile_definitions( ${builtins_link_lib_tgt} PRIVATE
312-
"__CLC_INTERNAL" )
313-
string( TOUPPER "-DCLC_${ARCH}" CLC_TARGET_DEFINE )
314-
target_compile_definitions( ${builtins_link_lib_tgt} PRIVATE
315-
${CLC_TARGET_DEFINE} )
316-
target_compile_options( ${builtins_link_lib_tgt} PRIVATE -target
317-
${t} ${mcpu} -fno-builtin -nostdlib ${build_flags} )
318-
set_target_properties( ${builtins_link_lib_tgt} PROPERTIES
319-
LINKER_LANGUAGE CLC )
320-
321-
set( obj_suffix ${arch_suffix}.bc )
322-
set( builtins_opt_lib_tgt builtins.opt.${obj_suffix} )
323-
324-
# Add opt target
325-
add_custom_command( OUTPUT ${builtins_opt_lib_tgt}
326-
COMMAND ${LLVM_OPT} ${opt_flags} -o ${builtins_opt_lib_tgt}
327-
$<TARGET_FILE:${builtins_link_lib_tgt}>
328-
DEPENDS ${builtins_link_lib_tgt} )
329-
add_custom_target( "opt.${obj_suffix}" ALL
330-
DEPENDS ${builtins_opt_lib_tgt} )
331-
332-
if( ${ARCH} STREQUAL "spirv" OR ${ARCH} STREQUAL "spirv64" )
308+
set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" )
309+
file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} )
310+
311+
string( TOUPPER "CLC_${ARCH}" CLC_TARGET_DEFINE )
312+
313+
list( APPEND build_flags
314+
-D__CLC_INTERNAL
315+
-D${CLC_TARGET_DEFINE}
316+
-I${PROJECT_SOURCE_DIR}/generic/include
317+
# FIXME: Fix libclc to not require disabling this noisy warnings
318+
-Wno-bitwise-conditional-parentheses
319+
)
320+
321+
set( bytecode_files "" )
322+
foreach( file IN LISTS gen_files rel_files )
323+
# We need to take each file and produce an absolute input file, as well
324+
# as a unique architecture-specific output file. We deal with a mix of
325+
# different input files, which makes this trickier.
326+
if( ${file} IN_LIST gen_files )
327+
# Generated files are given just as file names, which we must make
328+
# absolute to the binary directory.
329+
set( input_file ${CMAKE_CURRENT_BINARY_DIR}/${file} )
330+
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.o" )
331+
else()
332+
# Other files are originally relative to each SOURCE file, which are
333+
# then make relative to the libclc root directory. We must normalize
334+
# the path (e.g., ironing out any ".."), then make it relative to the
335+
# root directory again, and use that relative path component for the
336+
# binary path.
337+
get_filename_component( abs_path ${file} ABSOLUTE BASE_DIR ${PROJECT_SOURCE_DIR} )
338+
file( RELATIVE_PATH root_rel_path ${PROJECT_SOURCE_DIR} ${abs_path} )
339+
set( input_file ${PROJECT_SOURCE_DIR}/${file} )
340+
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.o" )
341+
endif()
342+
343+
get_filename_component( file_dir ${file} DIRECTORY )
344+
345+
compile_to_bc(
346+
TRIPLE ${clang_triple}
347+
INPUT ${input_file}
348+
OUTPUT ${output_file}
349+
EXTRA_OPTS "${mcpu}" -fno-builtin -nostdlib
350+
"${build_flags}" -I${PROJECT_SOURCE_DIR}/${file_dir}
351+
)
352+
list(APPEND bytecode_files ${output_file})
353+
endforeach()
354+
355+
set( builtins_link_lib_tgt builtins.link.${arch_suffix}.bc )
356+
357+
link_bc(
358+
OUTPUT ${builtins_link_lib_tgt}
359+
INPUTS ${bytecode_files}
360+
)
361+
362+
if( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
333363
set( spv_suffix ${arch_suffix}.spv )
334364
add_custom_command( OUTPUT "${spv_suffix}"
335-
COMMAND ${LLVM_SPIRV} ${spvflags} -o "${spv_suffix}" $<TARGET_FILE:${builtins_link_lib_tgt}>
365+
COMMAND ${LLVM_SPIRV} ${spvflags} -o "${spv_suffix}" ${builtins_link_lib_tgt}
336366
DEPENDS ${builtins_link_lib_tgt} )
337367
add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" )
338368
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix}
339369
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
340370
else()
371+
set( obj_suffix ${arch_suffix}.bc )
372+
set( builtins_opt_lib_tgt builtins.opt.${obj_suffix} )
373+
374+
# Add opt target
375+
add_custom_command( OUTPUT ${builtins_opt_lib_tgt}
376+
COMMAND libclc::opt ${opt_flags} -o ${builtins_opt_lib_tgt}
377+
${builtins_link_lib_tgt}
378+
DEPENDS ${builtins_link_lib_tgt} )
379+
add_custom_target( "opt.${obj_suffix}" ALL
380+
DEPENDS ${builtins_opt_lib_tgt} )
381+
341382
# Add prepare target
342383
add_custom_command( OUTPUT "${obj_suffix}"
343384
COMMAND prepare_builtins -o "${obj_suffix}" ${builtins_opt_lib_tgt}
344385
DEPENDS "opt.${obj_suffix}" ${builtins_opt_lib_tgt} prepare_builtins )
345386
add_custom_target( "prepare-${obj_suffix}" ALL DEPENDS "${obj_suffix}" )
346387

347388
# nvptx-- targets don't include workitem builtins
348-
if( NOT ${t} MATCHES ".*ptx.*--$" )
389+
if( NOT clang_triple MATCHES ".*ptx.*--$" )
349390
add_test( NAME external-calls-${obj_suffix}
350391
COMMAND ./check_external_calls.sh ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} ${LLVM_TOOLS_BINARY_DIR}
351392
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} )
352393
endif()
353394

354395
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
355396
foreach( a ${${d}_aliases} )
356-
set( alias_suffix "${a}-${t}.bc" )
397+
set( alias_suffix "${a}-${clang_triple}.bc" )
357398
add_custom_target( ${alias_suffix} ALL
358399
COMMAND ${CMAKE_COMMAND} -E create_symlink ${obj_suffix} ${alias_suffix}
359400
DEPENDS "prepare-${obj_suffix}" )

libclc/cmake/CMakeCLCCompiler.cmake.in

Lines changed: 0 additions & 9 deletions
This file was deleted.

libclc/cmake/CMakeCLCInformation.cmake

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)