-
Notifications
You must be signed in to change notification settings - Fork 79
/
CMakeLists.txt
356 lines (300 loc) · 12.6 KB
/
CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
cmake_minimum_required(VERSION 3.5)
set(LIBDIVIDE_VERSION "5.1")
project(libdivide C CXX)
include(CheckCXXCompilerFlag)
include(CheckCCompilerFlag)
include(CheckCXXSourceCompiles)
include(CheckCXXSourceRuns)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
include(CMakePushCheckState)
# Compile options ################################################
# Maximum warnings level & warnings as error
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") # clang-cl
add_compile_options("/W4;/WX;")
else() # clang native
add_compile_options("-Wall;-Wextra;-pedantic;-Werror")
endif()
else()
add_compile_options(
"$<$<CXX_COMPILER_ID:MSVC>:/W4;/WX>"
"$<$<CXX_COMPILER_ID:GNU>:-Wall;-Wextra;-pedantic;-Werror>"
"$<$<CXX_COMPILER_ID:AppleClang>:-Wall;-Wextra;-pedantic;-Werror>"
)
endif()
# Build options ################################################
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MAIN_PROJECT ON)
else()
set(MAIN_PROJECT OFF)
endif()
option(LIBDIVIDE_BUILD_TESTS "Build the test programs" "${MAIN_PROJECT}")
option(LIBDIVIDE_BUILD_FUZZERS "Build the fuzzers (requires clang)" OFF)
# By default we automatically enable vectors supported by
# the host CPU. You may also set these explicitly to OFF or ON.
set(LIBDIVIDE_SSE2 AUTO CACHE STRING "Enable SSE2 vector instructions")
set(LIBDIVIDE_AVX2 AUTO CACHE STRING "Enable AVX2 vector instructions")
set(LIBDIVIDE_AVX512 AUTO CACHE STRING "Enable AVX512 vector instructions")
set(LIBDIVIDE_NEON AUTO CACHE STRING "Enable ARM NEON vector instructions")
# By default enable release mode ###############################
if(NOT CMAKE_VERSION VERSION_LESS 3.9)
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
elseif(CMAKE_CONFIGURATION_TYPES)
set(isMultiConfig TRUE)
endif()
if(NOT isMultiConfig AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif()
# Enable assertions in debug mode ##############################
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
if("${BUILD_TYPE}" MATCHES DEBUG)
set(LIBDIVIDE_ASSERTIONS -DLIBDIVIDE_ASSERTIONS_ON)
endif()
# Try to warn about bogus vector conversions ###################
set(LIBDIVIDE_FLAGS)
check_cxx_compiler_flag(-fno-lax-vector-conversions WARN_VEC_CONVERSIONS)
if (WARN_VEC_CONVERSIONS)
list(APPEND LIBDIVIDE_FLAGS "-fno-lax-vector-conversions")
endif()
# Check if x86/x64 CPU ########################################
# Note that check_cxx_source_runs() must not be used when
# cross-compiling otherwise the following error will occur:
# CMake Error: TRY_RUN() invoked in cross-compiling mode, ...
if (LIBDIVIDE_BUILD_TESTS AND NOT CMAKE_CROSSCOMPILING)
check_cxx_source_compiles("
int main()
{
#if !defined(__i386__) && \
!defined(__x86_64__) && \
!defined(_M_IX86) && \
!defined(_M_X64)
#error not x86 CPU architecture
#endif
return 0;
}"
CPU_X86)
check_cxx_source_compiles("
#include <arm_neon.h>
int main()
{
#if !defined(__ARM_NEON)
#error not ARM NEON CPU architecture
#endif
return 0;
}"
CPU_ARM_NEON)
if (CPU_X86 OR CPU_ARM_NEON)
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS -Werror)
check_cxx_compiler_flag(-march=native MARCH_NATIVE)
cmake_pop_check_state()
if (MARCH_NATIVE)
list(APPEND LIBDIVIDE_FLAGS "-march=native")
endif()
endif()
endif()
# Disable auto vectorization ###################################
# We disable auto vectorization on x86 (and x64-64) in order
# to prevent the compiler from vectorizing our scalar benchmarks
# which would make the benchmark results less useful.
if(CPU_X86 OR CPU_ARM_NEON)
# first check the C++ compiler
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
check_cxx_compiler_flag("-fno-vectorize" fno_vectorize)
if(fno_vectorize)
set(NO_VECTORIZE -fno-vectorize)
endif()
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
check_cxx_compiler_flag("-fno-tree-vectorize" fno_tree_vectorize)
if(fno_tree_vectorize)
set(NO_VECTORIZE -fno-tree-vectorize)
endif()
endif()
# then check the C compiler
if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
check_c_compiler_flag("-fno-vectorize" fno_vectorize_c)
if(fno_vectorize_c)
set(NO_VECTORIZE_C -fno-vectorize)
endif()
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
check_c_compiler_flag("-fno-tree-vectorize" fno_tree_vectorize_c)
if(fno_tree_vectorize_c)
set(NO_VECTORIZE_C -fno-tree-vectorize)
endif()
endif()
endif()
# Resolve any "auto" supported vector types ##################
# Note these use "check_cxx_source_runs" and not "check_cxx_source_compiles"
# because VC++ will compile AVX512 even though it's not available at runtime.
cmake_push_check_state()
# Need to convert from list to space-separated string.
string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${LIBDIVIDE_FLAGS}")
# NEON
if (NOT LIBDIVIDE_NEON STREQUAL "AUTO")
set(LIBDIVIDE_NEON_ENABLED "${LIBDIVIDE_NEON}")
else()
set(NEON_TEST "
#include <arm_neon.h>
int main()
{
int32x4_t a = vdupq_n_s32(0);
return *(int *)&a;
}")
if (CMAKE_CROSSCOMPILING)
check_cxx_source_compiles("${NEON_TEST}" LIBDIVIDE_NEON_ENABLED)
else()
check_cxx_source_runs("${NEON_TEST}" LIBDIVIDE_NEON_ENABLED)
endif()
endif()
# AVX512
if (NOT LIBDIVIDE_AVX512 STREQUAL "AUTO")
set(LIBDIVIDE_AVX512_ENABLED "${LIBDIVIDE_AVX512}")
else()
check_cxx_source_runs("
#include <immintrin.h>
int main()
{
__m512i a = _mm512_setzero_si512();
return *(int *)&a;
}"
LIBDIVIDE_AVX512_ENABLED)
endif()
# AVX2
if (NOT LIBDIVIDE_AVX2 STREQUAL "AUTO")
set(LIBDIVIDE_AVX2_ENABLED "${LIBDIVIDE_AVX2}")
else()
# Need to use an AVX2 insn like srai, not just AVX.
check_cxx_source_runs("
#include <immintrin.h>
int main()
{
__m256i a = _mm256_srai_epi32(_mm256_setzero_si256(), 3);
return *(int *)&a;
}"
LIBDIVIDE_AVX2_ENABLED)
endif()
# SSE2
if (NOT LIBDIVIDE_SSE2 STREQUAL "AUTO")
set(LIBDIVIDE_SSE2_ENABLED "${LIBDIVIDE_SSE2}")
else()
check_cxx_source_runs("
#include <emmintrin.h>
int main()
{
__m128i a = _mm_setzero_si128();
return *(int *)&a;
}"
LIBDIVIDE_SSE2_ENABLED)
endif()
cmake_pop_check_state()
# Populate LIBDIVIDE_VECTOR_EXT ##################
set(LIBDIVIDE_VECTOR_EXT "")
if(LIBDIVIDE_NEON_ENABLED)
list(APPEND LIBDIVIDE_VECTOR_EXT "LIBDIVIDE_NEON")
endif()
if(LIBDIVIDE_AVX512_ENABLED)
list(APPEND LIBDIVIDE_VECTOR_EXT "LIBDIVIDE_AVX512")
endif()
if(LIBDIVIDE_AVX2_ENABLED)
list(APPEND LIBDIVIDE_VECTOR_EXT "LIBDIVIDE_AVX2")
endif()
if(LIBDIVIDE_SSE2_ENABLED)
list(APPEND LIBDIVIDE_VECTOR_EXT "LIBDIVIDE_SSE2")
endif()
# libdivide header-only library target #########################
add_library(libdivide INTERFACE)
add_library(libdivide::libdivide ALIAS libdivide)
include(CMakeSanitize)
target_compile_features(libdivide INTERFACE cxx_alias_templates)
target_include_directories(libdivide INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
install(FILES libdivide.h
COMPONENT libdivide-header
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
# CMake find_package(libdivide) support ########################
install(TARGETS libdivide
EXPORT libdivideConfig
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
export(TARGETS libdivide
NAMESPACE libdivide::
FILE "${CMAKE_CURRENT_BINARY_DIR}/libdivideConfig.cmake")
install(EXPORT libdivideConfig
NAMESPACE libdivide::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/libdivide")
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/libdivideConfigVersion.cmake"
VERSION ${LIBDIVIDE_VERSION}
COMPATIBILITY SameMajorVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivideConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/libdivide")
# Build test programs ##########################################
if (LIBDIVIDE_BUILD_TESTS)
find_package(Threads REQUIRED QUIET)
add_executable(tester test/tester.cpp)
add_executable(test_c99 test/test_c99.c)
add_executable(fast_div_generator test/fast_div_generator.cpp)
add_executable(benchmark test/benchmark.cpp)
add_executable(benchmark_branchfree test/benchmark_branchfree.cpp)
target_link_libraries(tester libdivide Threads::Threads)
target_link_libraries(test_c99 libdivide)
target_link_libraries(fast_div_generator libdivide)
target_link_libraries(benchmark libdivide)
target_link_libraries(benchmark_branchfree libdivide)
target_compile_options(tester PRIVATE "${LIBDIVIDE_FLAGS}" "${NO_VECTORIZE}")
target_compile_options(test_c99 PRIVATE "${LIBDIVIDE_FLAGS}" "${NO_VECTORIZE}")
target_compile_options(fast_div_generator PRIVATE "${LIBDIVIDE_FLAGS}" "${NO_VECTORIZE}")
target_compile_options(benchmark PRIVATE "${LIBDIVIDE_FLAGS}" "${NO_VECTORIZE_C}")
target_compile_options(benchmark_branchfree PRIVATE "${LIBDIVIDE_FLAGS}" "${NO_VECTORIZE}")
set_property(TARGET benchmark_branchfree PROPERTY CXX_STANDARD 11)
set_property(TARGET test_c99 PROPERTY C_STANDARD 99)
target_compile_definitions(tester PRIVATE "${LIBDIVIDE_ASSERTIONS}" "${LIBDIVIDE_VECTOR_EXT}")
target_compile_definitions(test_c99 PRIVATE "${LIBDIVIDE_ASSERTIONS}" "${LIBDIVIDE_VECTOR_EXT}")
target_compile_definitions(fast_div_generator PRIVATE "${LIBDIVIDE_ASSERTIONS}" "${LIBDIVIDE_VECTOR_EXT}")
target_compile_definitions(benchmark PRIVATE "${LIBDIVIDE_ASSERTIONS}" "${LIBDIVIDE_VECTOR_EXT}")
target_compile_definitions(benchmark_branchfree PRIVATE "${LIBDIVIDE_ASSERTIONS}" "${LIBDIVIDE_VECTOR_EXT}")
endif()
# Enable testing ###############################################
if (LIBDIVIDE_BUILD_TESTS)
include(CTest)
enable_testing()
add_test(tester tester)
# cmake won't actually build the tests before it tries to run them
add_test(build_tester "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target tester)
set_tests_properties(tester PROPERTIES DEPENDS "build_tester")
add_test(test_c99 test_c99)
add_test(build_test_c99 "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target test_c99)
set_tests_properties(test_c99 PROPERTIES DEPENDS "build_test_c99")
# Only benchmark in release builds.
if("${BUILD_TYPE}" MATCHES RELEASE)
add_test(benchmark_branchfree benchmark_branchfree)
add_test(build_benchmark_branchfree "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target benchmark_branchfree)
set_tests_properties(benchmark_branchfree PROPERTIES DEPENDS "build_benchmark_branchfree")
endif()
endif()
# Build the fuzzers (requires clang) ###########################
if (LIBDIVIDE_BUILD_FUZZERS)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(fuzzflags "-fsanitize=fuzzer,address")
add_executable(fuzzer_scalar test/fuzzer_scalar.cpp)
target_compile_features(fuzzer_scalar PRIVATE cxx_std_17)
target_link_libraries(fuzzer_scalar PRIVATE "${fuzzflags}")
target_compile_options(fuzzer_scalar PRIVATE "${NATIVE_FLAG}" "${NO_VECTORIZE}" "${fuzzflags}")
target_compile_definitions(fuzzer_scalar PRIVATE "${LIBDIVIDE_ASSERTIONS}")
target_link_libraries(fuzzer_scalar PRIVATE libdivide)
if (LIBDIVIDE_VECTOR_EXT)
add_executable(fuzzer_simd test/fuzzer_simd.cpp)
target_compile_features(fuzzer_simd PRIVATE cxx_std_17)
target_link_libraries(fuzzer_simd PRIVATE "${fuzzflags}")
target_compile_options(fuzzer_simd PRIVATE "${NATIVE_FLAG}" "${NO_VECTORIZE}" "${fuzzflags}")
target_compile_definitions(fuzzer_simd PRIVATE "${LIBDIVIDE_ASSERTIONS}" "${LIBDIVIDE_VECTOR_EXT}")
target_link_libraries(fuzzer_simd PRIVATE libdivide)
endif()
else()
message(FATAL_ERROR "You must use clang to build the fuzzers (uses libFuzzer)")
endif()
endif()