Skip to content

Commit 0acedec

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_SUBORMAL when configuring CMake.
1 parent 61efea7 commit 0acedec

12 files changed

+213
-276
lines changed

libclc/CMakeLists.txt

Lines changed: 118 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ 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+
include( AddLibclc )
11+
712
include( GNUInstallDirs )
813
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
914
amdgcn-amdhsa/lib/SOURCES;
@@ -27,31 +32,47 @@ set( LIBCLC_TARGETS_TO_BUILD "all"
2732

2833
option( ENABLE_RUNTIME_SUBNORMAL "Enable runtime linking of subnormal support." OFF )
2934

30-
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
31-
include(AddLLVM)
35+
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
36+
# Out-of-tree configuration
37+
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
38+
include(AddLLVM)
3239

33-
message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )
40+
message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )
3441

35-
if( ${LLVM_PACKAGE_VERSION} VERSION_LESS ${LIBCLC_MIN_LLVM} )
36-
message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
37-
endif()
42+
if( ${LLVM_PACKAGE_VERSION} VERSION_LESS ${LIBCLC_MIN_LLVM} )
43+
message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
44+
endif()
3845

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 )
46+
# Import required tools as targets
47+
foreach( tool clang llvm-as llvm-link opt )
48+
find_program( LLVM_TOOL_${tool} ${tool} PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
49+
add_executable( libclc::${tool} IMPORTED GLOBAL )
50+
set_target_properties( libclc::${tool} PROPERTIES IMPORTED_LOCATION ${LLVM_TOOL_${tool}} )
51+
endforeach()
52+
else()
53+
# In-tree configuration
54+
set( LLVM_PACKAGE_VERSION ${LLVM_VERSION} )
55+
56+
# Note that we check this later (for both build types) but we can provide a
57+
# more useful error message when built in-tree. We assume that LLVM tools are
58+
# always available so don't warn here.
59+
if( NOT clang IN_LIST LLVM_ENABLE_PROJECTS )
60+
message(FATAL_ERROR "Clang is not enabled, but is required to build libclc in-tree")
61+
endif()
4462

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 )
63+
foreach( tool clang llvm-as llvm-link opt )
64+
add_executable(libclc::${tool} ALIAS ${tool})
65+
endforeach()
66+
endif()
67+
68+
if( NOT TARGET libclc::clang OR NOT TARGET libclc::opt
69+
OR NOT TARGET libclc::llvm-as OR NOT TARGET libclc::llvm-link )
5270
message( FATAL_ERROR "libclc toolchain incomplete!" )
5371
endif()
5472

73+
# llvm-spirv is an optional dependency, used to build spirv-* targets.
74+
find_program( LLVM_SPIRV llvm-spirv PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
75+
5576
# List of all targets. Note that some are added dynamically below.
5677
set( LIBCLC_TARGETS_ALL
5778
amdgcn--
@@ -66,7 +87,7 @@ set( LIBCLC_TARGETS_ALL
6687
)
6788

6889
# mesa3d environment is only available since LLVM 4.0
69-
if( ${LLVM_PACKAGE_VERSION} VERSION_GREATER "3.9.0" )
90+
if( ${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL 4.0.0 )
7091
list( APPEND LIBCLC_TARGETS_ALL amdgcn-mesa-mesa3d )
7192
endif()
7293

@@ -90,24 +111,9 @@ if( "spirv-mesa3d-" IN_LIST LIBCLC_TARGETS_TO_BUILD OR "spirv64-mesa3d-" IN_LIST
90111
endif()
91112
endif()
92113

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-
100114
# Construct LLVM version define
101115
set( LLVM_VERSION_DEFINE "-DHAVE_LLVM=0x${LLVM_VERSION_MAJOR}0${LLVM_VERSION_MINOR}" )
102116

103-
104-
# LLVM 13 enables standard includes by default
105-
if( ${LLVM_PACKAGE_VERSION} VERSION_GREATER "12.99.99" )
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 )
111117
# This needs to be set before any target that needs it
112118
# We need to use LLVM_INCLUDE_DIRS here, because if we are linking to an
113119
# llvm build directory, this includes $src/llvm/include which is where all the
@@ -162,13 +168,18 @@ configure_file( libclc.pc.in libclc.pc @ONLY )
162168
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libclc.pc DESTINATION "${CMAKE_INSTALL_DATADIR}/pkgconfig" )
163169
install( DIRECTORY generic/include/clc DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" )
164170

171+
set( LIBCLC_OBJFILE_DIR "${CMAKE_CURRENT_BINARY_DIR}/obj.libclc.dir" )
172+
165173
if( ENABLE_RUNTIME_SUBNORMAL )
166-
add_library( subnormal_use_default STATIC
167-
generic/lib/subnormal_use_default.ll )
168-
add_library( subnormal_disable STATIC
169-
generic/lib/subnormal_disable.ll )
170-
install( TARGETS subnormal_use_default subnormal_disable ARCHIVE
171-
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
174+
foreach( file subnormal_use_default subnormal_disable )
175+
link_bc(
176+
OUTPUT ${LIBCLC_OBJFILE_DIR}/${file}.bc
177+
INPUTS ${PROJECT_SOURCE_DIR}/generic/lib/${file}.ll
178+
)
179+
add_custom_target( ${file}.bc ALL DEPENDS ${LIBCLC_OBJFILE_DIR}/${file}.bc )
180+
install( FILES ${LIBCLC_OBJFILE_DIR}/${file}.bc ARCHIVE
181+
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
182+
endforeach()
172183
endif()
173184

174185
find_package( Python3 REQUIRED COMPONENTS Interpreter )
@@ -205,7 +216,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
205216
list( APPEND dirs amdgpu )
206217
endif()
207218

208-
#nvptx is special
219+
# nvptx is special
209220
if( ${ARCH} STREQUAL nvptx OR ${ARCH} STREQUAL nvptx64 )
210221
set( DARCH ptx )
211222
else()
@@ -226,38 +237,32 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
226237
endforeach()
227238
endforeach()
228239

229-
# Add the generated convert.cl here to prevent adding
230-
# the one listed in SOURCES
240+
# Add the generated convert.cl here to prevent adding the one listed in
241+
# SOURCES
242+
set( objects ) # A "set" of already-added input files
243+
set( rel_files ) # Source directory input files, relative to the root dir
244+
set( gen_files ) # Generated binary input files, relative to the binary dir
231245
if( NOT ${ARCH} STREQUAL "spirv" AND NOT ${ARCH} STREQUAL "spirv64" )
232246
if( NOT ENABLE_RUNTIME_SUBNORMAL AND NOT ${ARCH} STREQUAL "clspv" AND
233247
NOT ${ARCH} STREQUAL "clspv64" )
234-
set( rel_files convert.cl )
235-
set( objects convert.cl )
248+
list( APPEND gen_files convert.cl )
249+
list( APPEND objects convert.cl )
236250
list( APPEND rel_files generic/lib/subnormal_use_default.ll )
237251
elseif(${ARCH} STREQUAL "clspv" OR ${ARCH} STREQUAL "clspv64")
238-
set( rel_files clspv-convert.cl )
239-
set( objects clspv-convert.cl )
252+
list( APPEND gen_files clspv-convert.cl )
253+
list( APPEND objects clspv-convert.cl )
240254
endif()
241-
else()
242-
set( rel_files )
243-
set( objects )
244255
endif()
245256

246257
foreach( l ${source_list} )
247258
file( READ ${l} file_list )
248259
string( REPLACE "\n" ";" file_list ${file_list} )
249260
get_filename_component( dir ${l} DIRECTORY )
250261
foreach( f ${file_list} )
251-
list( FIND objects ${f} found )
252-
if( found EQUAL -1 )
262+
# Only add each file once, so that targets can 'specialize' builtins
263+
if( NOT ${f} IN_LIST objects )
253264
list( APPEND objects ${f} )
254265
list( APPEND rel_files ${dir}/${f} )
255-
# FIXME: This should really go away
256-
file( TO_CMAKE_PATH ${PROJECT_SOURCE_DIR}/${dir}/${f} src_loc )
257-
get_filename_component( fdir ${src_loc} DIRECTORY )
258-
259-
set_source_files_properties( ${dir}/${f}
260-
PROPERTIES COMPILE_FLAGS "-I ${fdir}" )
261266
endif()
262267
endforeach()
263268
endforeach()
@@ -295,32 +300,67 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
295300
set( opt_flags -O3 )
296301
endif()
297302

298-
set( builtins_link_lib_tgt builtins.link.${arch_suffix} )
299-
add_library( ${builtins_link_lib_tgt} STATIC ${rel_files} )
300-
# Make sure we depend on the pseudo target to prevent
301-
# multiple invocations
302-
add_dependencies( ${builtins_link_lib_tgt} generate_convert.cl )
303-
add_dependencies( ${builtins_link_lib_tgt} clspv-generate_convert.cl )
304-
# CMake will turn this include into absolute path
305-
target_include_directories( ${builtins_link_lib_tgt} PRIVATE
306-
"generic/include" )
307-
target_compile_definitions( ${builtins_link_lib_tgt} PRIVATE
308-
"__CLC_INTERNAL" )
309-
string( TOUPPER "-DCLC_${ARCH}" CLC_TARGET_DEFINE )
310-
target_compile_definitions( ${builtins_link_lib_tgt} PRIVATE
311-
${CLC_TARGET_DEFINE} )
312-
target_compile_options( ${builtins_link_lib_tgt} PRIVATE -target
313-
${t} ${mcpu} -fno-builtin -nostdlib ${build_flags} )
314-
set_target_properties( ${builtins_link_lib_tgt} PROPERTIES
315-
LINKER_LANGUAGE CLC )
303+
set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" )
304+
file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} )
305+
306+
string( TOUPPER "CLC_${ARCH}" CLC_TARGET_DEFINE )
307+
308+
list( APPEND build_flags
309+
-D__CLC_INTERNAL
310+
-D${CLC_TARGET_DEFINE}
311+
-I${PROJECT_SOURCE_DIR}/generic/include
312+
# FIXME: Fix libclc to not require disabling this noisy warnings
313+
-Wno-bitwise-conditional-parentheses
314+
)
315+
316+
set( bytecode_files "" )
317+
foreach( file IN LISTS gen_files rel_files )
318+
# We need to take each file and produce an absolute input file, as well
319+
# as a unique architecture-specific output file. We deal with a mix of
320+
# different input files, which makes this trickier.
321+
if( ${file} IN_LIST gen_files )
322+
# Generated files are given just as file names, which we must make
323+
# absolute to the binary directory.
324+
set( input_file ${CMAKE_CURRENT_BINARY_DIR}/${file} )
325+
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.o" )
326+
else()
327+
# Other files are originally relative to each SOURCE file, which are
328+
# then make relative to the libclc root directory. We must normalize
329+
# the path (e.g., ironing out any ".."), then make it relative to the
330+
# root directory again, and use that relative path component for the
331+
# binary path.
332+
get_filename_component( abs_path ${file} ABSOLUTE BASE_DIR ${PROJECT_SOURCE_DIR} )
333+
file( RELATIVE_PATH root_rel_path ${PROJECT_SOURCE_DIR} ${abs_path} )
334+
set( input_file ${PROJECT_SOURCE_DIR}/${file} )
335+
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.o" )
336+
endif()
337+
338+
get_filename_component( file_dir ${file} DIRECTORY )
339+
340+
compile_to_bc(
341+
TRIPLE ${t}
342+
INPUT ${input_file}
343+
OUTPUT ${output_file}
344+
EXTRA_OPTS "${mcpu}" -fno-builtin -nostdlib
345+
"${build_flags}" -I${PROJECT_SOURCE_DIR}/${file_dir}
346+
)
347+
list(APPEND bytecode_files ${output_file})
348+
endforeach()
349+
350+
set( builtins_link_lib_tgt builtins.link.${arch_suffix}.bc )
351+
352+
link_bc(
353+
OUTPUT ${builtins_link_lib_tgt}
354+
INPUTS ${bytecode_files}
355+
)
316356

317357
set( obj_suffix ${arch_suffix}.bc )
318358
set( builtins_opt_lib_tgt builtins.opt.${obj_suffix} )
319359

320360
# Add opt target
321361
add_custom_command( OUTPUT ${builtins_opt_lib_tgt}
322-
COMMAND ${LLVM_OPT} ${opt_flags} -o ${builtins_opt_lib_tgt}
323-
$<TARGET_FILE:${builtins_link_lib_tgt}>
362+
COMMAND libclc::opt ${opt_flags} -o ${builtins_opt_lib_tgt}
363+
${builtins_link_lib_tgt}
324364
DEPENDS ${builtins_link_lib_tgt} )
325365
add_custom_target( "opt.${obj_suffix}" ALL
326366
DEPENDS ${builtins_opt_lib_tgt} )

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.

libclc/cmake/CMakeDetermineCLCCompiler.cmake

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

libclc/cmake/CMakeDetermineLLAsmCompiler.cmake

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

libclc/cmake/CMakeLLAsmCompiler.cmake.in

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

libclc/cmake/CMakeLLAsmInformation.cmake

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

0 commit comments

Comments
 (0)