Skip to content

Commit 26cf1ab

Browse files
authored
Make the cmake & CI builds use the same settings (ridiculousfish#82)
* CI & CMake builds: use same warning level Turn on all warnings & warnings as errors CI build will build debug as well as release (to get assertions). * Add sanitize options to CMake And replace build only sanitize flags with the cmake option. * CI build fixes * Install VS 2019 ASAN component * Docs * Use a seperate build config - Sanitize Instead of applying flags to existing build configs. * Code review feedback
1 parent 3295059 commit 26cf1ab

13 files changed

+186
-59
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ CTestTestfile.cmake
1616
.DS_Store
1717
.pio
1818
.vscode/*
19-
!.vscode/extensions.json
19+
!.vscode/extensions.json
20+
!.vscode/cmake-variants.json

.vscode/cmake-variants.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"buildType": {
3+
"default": "debug",
4+
"choices": {
5+
"debug": {
6+
"short": "Debug",
7+
"long": "Disable optimizations - include debug information.",
8+
"buildType": "Debug"
9+
},
10+
"release": {
11+
"short": "Release",
12+
"long": "Optimize for speed - exclude debug information.",
13+
"buildType": "Release"
14+
},
15+
"reldebuginfo": {
16+
"short": "Release with debug Info",
17+
"long": "Optimize for speed - include debug information.",
18+
"buildType": "RelWithDebInfo"
19+
},
20+
"sanitize": {
21+
"short": "Release with sanitizers",
22+
"long": "Fast sanitization checks.",
23+
"buildType": "Sanitize"
24+
}
25+
}
26+
}
27+
}

CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ include(CheckCXXSourceRuns)
99
include(GNUInstallDirs)
1010
include(CMakePackageConfigHelpers)
1111
include(CMakePushCheckState)
12+
include(CMakeSanitize)
13+
14+
# Compile options ################################################
15+
16+
# Maximum warnings level & warnings as error
17+
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/W4;/WX>")
18+
add_compile_options("$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wall;-Wextra;-pedantic;-Werror>")
1219

1320
# Build options ################################################
1421

CMakeSanitize

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
set(BUILD_NAME "Sanitize")
2+
string(TOUPPER "${BUILD_NAME}" BUILD_NAME_U)
3+
4+
set(BASE_BUILD_NAME "RelWithDebInfo")
5+
string(TOUPPER "${BASE_BUILD_NAME}" BASE_BUILD_NAME_U)
6+
7+
if(CMAKE_CONFIGURATION_TYPES)
8+
list(APPEND CMAKE_CONFIGURATION_TYPES "${BUILD_NAME}")
9+
list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES)
10+
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
11+
"Add the configurations that we need"
12+
FORCE)
13+
endif()
14+
15+
if (CMAKE_C_COMPILER_ID STREQUAL "MSVC")
16+
set(COMPILER_FLAGS "/fsanitize=address /MTd")
17+
set(LINKER_FLAGS "/INCREMENTAL:NO")
18+
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
19+
set(COMPILER_FLAGS "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -U_DLL -U_MT -DDEBUG -O1 -g")
20+
set(LINKER_FLAGS "-fsanitize=address")
21+
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
22+
set(COMPILER_FLAGS "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -DDEBUG -O1 -g")
23+
set(LINKER_FLAGS "-fsanitize=address -fsanitize=undefined")
24+
endif()
25+
26+
set("CMAKE_CXX_FLAGS_${BUILD_NAME_U}" "${CMAKE_CXX_FLAGS_${BASE_BUILD_NAME_U}} ${COMPILER_FLAGS}" CACHE STRING
27+
"Flags used by the C++ compiler during ${BUILD_NAME} builds."
28+
FORCE)
29+
set("CMAKE_C_FLAGS_${BUILD_NAME_U}" "${CMAKE_C_FLAGS_${BASE_BUILD_NAME_U}} ${COMPILER_FLAGS}" CACHE STRING
30+
"Flags used by the C compiler during ${BUILD_NAME} builds."
31+
FORCE)
32+
set("CMAKE_EXE_LINKER_FLAGS_${BUILD_NAME_U}" "${CMAKE_EXE_LINKER_FLAGS_${BASE_BUILD_NAME_U}} ${LINKER_FLAGS}" CACHE STRING
33+
"Flags used for linking binaries during ${BUILD_NAME} builds."
34+
FORCE)
35+
set("CMAKE_SHARED_LINKER_FLAGS_${BUILD_NAME_U}" "${CMAKE_SHARED_LINKER_FLAGS_${BASE_BUILD_NAME_U}} ${LINKER_FLAGS}" CACHE STRING
36+
"Flags used by the shared libraries linker during ${BUILD_NAME} builds."
37+
FORCE)
38+
39+
mark_as_advanced(
40+
"${CMAKE_CXX_FLAGS_${BUILD_NAME_U}}"
41+
"${CMAKE_C_FLAGS_${BUILD_NAME_U}}"
42+
"${CMAKE_EXE_LINKER_FLAGS_${BUILD_NAME_U}}"
43+
"${CMAKE_SHARED_LINKER_FLAGS_${BUILD_NAME_U}}")
44+
45+
# Update the documentation string of CMAKE_BUILD_TYPE for GUIs
46+
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
47+
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ${BUILD_NAME}."
48+
FORCE)

README.md

+11-6
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ discrepancy.
187187

188188
# Benchmark program
189189

190-
You can pass the **benchmark** program one or more of the following arguments: ```u32```,
190+
You can pass the **benchmark** program one or more of the following arguments: ```u16```, ```s16```, ```u32```,
191191
```s32```, ```u64```, ```s64``` to compare libdivide's speed against hardware division.
192192
**benchmark** tests a simple function that inputs an array of random numerators and a single
193193
divisor, and returns the sum of their quotients. It tests this using both hardware division, and
@@ -210,7 +210,7 @@ It will keep going as long as you let it, so it's best to stop it when you are h
210210
denominators tested. These columns have the following significance. All times are in
211211
nanoseconds, lower is better.
212212

213-
```bash
213+
```
214214
#: The divisor that is tested
215215
system: Hardware divide time
216216
scalar: libdivide time, using scalar division
@@ -226,9 +226,14 @@ so benchmark is valuable for its verification as well.
226226

227227
# Contributing
228228

229-
We currently do not have automated testing! Hence, before sending in patches, it would be nice
230-
if you compiled your new code at high warning levels using at least MSVC and GCC (or Clang).
231-
Also run the tester program to verify correctness and the benchmark programs to ensure you have
232-
not introduced any performance regressions.
229+
Although there are no individual unit tests, the supplied ```cmake``` builds do include several safety nets:
230+
231+
* They compile with:
232+
* All warnings on and;
233+
* Warnings as errors
234+
* The CI build will build and run with sanitizers on ; these are available as part of the cmake build: ```-DCMAKE_BUILD_TYPE=Sanitize```
235+
* The ```cmake``` and CI builds will compile and run both ```C``` and ```C++``` test programs.
236+
237+
Before sending in patches, build and run at least the ```tester``` and ```benchmark``` using the supplied ```cmake``` scripts on at least ```MSVC``` and ```GCC``` (or ```Clang```).
233238

234239
### Happy hacking!

appveyor.yml

+12-18
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@ for:
1717
only:
1818
- image: Ubuntu1804
1919
platform: x86
20-
environment:
21-
CFLAGS: "-Wall -Wextra -pedantic -Werror -O1 -g -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
22-
CXXFLAGS: "-Wall -Wextra -pedantic -Werror -O1 -g -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
2320
install:
2421
- sudo apt install --yes cppcheck
2522
build_script:
26-
- cmake . -DCMAKE_BUILD_TYPE=Debug
23+
- cmake . -DCMAKE_BUILD_TYPE=Sanitize
2724
- make VERBOSE=1
2825
test_script:
2926
- cppcheck . --error-exitcode=1 --force -i doc
@@ -35,13 +32,10 @@ for:
3532
only:
3633
- image: Ubuntu1804
3734
platform: x64
38-
environment:
39-
CFLAGS: "-Wall -Wextra -pedantic -Werror -O1 -g -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
40-
CXXFLAGS: "-Wall -Wextra -pedantic -Werror -O1 -g -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
4135
install:
4236
- sudo apt install --yes cppcheck
4337
build_script:
44-
- CC=clang CXX=clang++ cmake . -DCMAKE_BUILD_TYPE=Debug
38+
- CC=clang CXX=clang++ cmake . -DCMAKE_BUILD_TYPE=Sanitize
4539
- make VERBOSE=1
4640
test_script:
4741
- cppcheck . --error-exitcode=1 --force -i doc
@@ -66,11 +60,9 @@ for:
6660
only:
6761
- image: Visual Studio 2017
6862
platform: x64
69-
environment:
70-
CFLAGS: "/W3 /WX /DLIBDIVIDE_ASSERTIONS_ON"
71-
CXXFLAGS: "/W3 /WX /DLIBDIVIDE_ASSERTIONS_ON"
7263
build_script:
7364
- cmake . -G "Visual Studio 15 2017 Win64"
65+
- cmake --build . --config Debug
7466
- cmake --build . --config Release
7567
test_script:
7668
- cd Release
@@ -82,11 +74,14 @@ for:
8274
only:
8375
- image: Visual Studio 2019
8476
platform: x86
77+
install:
78+
- cmd: '"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vs_installer.exe" modify --quiet --installpath "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" --channelid VisualStudio.16.Release --productid Microsoft.VisualStudio.Product.Community --add Microsoft.VisualStudio.Component.VC.ASAN'
8579
build_script:
8680
- cmake . -G "Visual Studio 16 2019"
87-
- cmake --build . --config Release
81+
- cmake --build . --config Debug
82+
- cmake --build . --config Sanitize
8883
test_script:
89-
- cd Release
84+
- cd Sanitize
9085
- tester.exe
9186
- benchmark_branchfree.exe
9287
- test_c99.exe
@@ -95,23 +90,22 @@ for:
9590
only:
9691
- image: Visual Studio 2019
9792
platform: x64
98-
environment:
99-
CFLAGS: "/W3 /WX /DLIBDIVIDE_ASSERTIONS_ON"
100-
CXXFLAGS: "/W3 /WX /DLIBDIVIDE_ASSERTIONS_ON"
10193
install:
94+
- cmd: '"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vs_installer.exe" modify --quiet --installpath "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" --channelid VisualStudio.16.Release --productid Microsoft.VisualStudio.Product.Community --add Microsoft.VisualStudio.Component.VC.ASAN'
10295
- cmd: SET PATH=C:\Python39;C:\Python39\Scripts;%PATH%
10396
- cmd: pip install -U platformio
10497
- cmd: pio platform install atmelavr --with-package=tool-simavr
10598
build_script:
10699
- cmake . -G "Visual Studio 16 2019"
107-
- cmake --build . --config Release
100+
- cmake --build . --config Debug
101+
- cmake --build . --config Sanitize
108102
- cd test/avr
109103
- ps: Get-Content -Path .\platformio.ini | Where-Object { $_.StartsWith("[env:") } | ForEach-Object { & pio run -e $_.SubString(5, $_.Length-6) }
110104
- cd ../..
111105
test_script:
112106
# Important check for AVR - static + inline
113107
- ps: Select-String -Path "libdivide.h" "static [^L]" -AllMatches | ForEach-Object { Write-Error ("Static but not line - " + $_) }
114-
- cd Release
108+
- cd Sanitize
115109
- tester.exe
116110
- benchmark_branchfree.exe
117111
- test_c99.exe

libdivide.h

+20-10
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,15 @@
3333

3434
#if defined(_MSC_VER)
3535
#include <intrin.h>
36+
#pragma warning(push)
3637
// disable warning C4146: unary minus operator applied
3738
// to unsigned type, result still unsigned
3839
#pragma warning(disable : 4146)
40+
// disable warning C4204: nonstandard extension used : non-constant aggregate
41+
// initializer
42+
//
43+
// It's valid C99
44+
#pragma warning(disable : 4204)
3945
#define LIBDIVIDE_VC
4046
#endif
4147

@@ -869,7 +875,7 @@ static LIBDIVIDE_INLINE struct libdivide_u32_t libdivide_internal_u32_gen(
869875
// This power works if e < 2**floor_log_2_d.
870876
if (!branchfree && (e < ((uint32_t)1 << floor_log_2_d))) {
871877
// This power works
872-
more = floor_log_2_d;
878+
more = (uint8_t)floor_log_2_d;
873879
} else {
874880
// We have to use the general 33-bit algorithm. We need to compute
875881
// (2**power) / d. However, we already have (2**(power-1))/d and
@@ -879,7 +885,7 @@ static LIBDIVIDE_INLINE struct libdivide_u32_t libdivide_internal_u32_gen(
879885
proposed_m += proposed_m;
880886
const uint32_t twice_rem = rem + rem;
881887
if (twice_rem >= d || twice_rem < rem) proposed_m += 1;
882-
more = floor_log_2_d | LIBDIVIDE_ADD_MARKER;
888+
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
883889
}
884890
result.magic = 1 + proposed_m;
885891
result.more = more;
@@ -1028,7 +1034,7 @@ static LIBDIVIDE_INLINE struct libdivide_u64_t libdivide_internal_u64_gen(
10281034
// This power works if e < 2**floor_log_2_d.
10291035
if (!branchfree && e < ((uint64_t)1 << floor_log_2_d)) {
10301036
// This power works
1031-
more = floor_log_2_d;
1037+
more = (uint8_t)floor_log_2_d;
10321038
} else {
10331039
// We have to use the general 65-bit algorithm. We need to compute
10341040
// (2**power) / d. However, we already have (2**(power-1))/d and
@@ -1038,7 +1044,7 @@ static LIBDIVIDE_INLINE struct libdivide_u64_t libdivide_internal_u64_gen(
10381044
proposed_m += proposed_m;
10391045
const uint64_t twice_rem = rem + rem;
10401046
if (twice_rem >= d || twice_rem < rem) proposed_m += 1;
1041-
more = floor_log_2_d | LIBDIVIDE_ADD_MARKER;
1047+
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
10421048
}
10431049
result.magic = 1 + proposed_m;
10441050
result.more = more;
@@ -1368,7 +1374,7 @@ static LIBDIVIDE_INLINE struct libdivide_s32_t libdivide_internal_s32_gen(
13681374
if ((absD & (absD - 1)) == 0) {
13691375
// Branchfree and normal paths are exactly the same
13701376
result.magic = 0;
1371-
result.more = floor_log_2_d | (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0);
1377+
result.more = (uint8_t)(floor_log_2_d | (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0));
13721378
} else {
13731379
LIBDIVIDE_ASSERT(floor_log_2_d >= 1);
13741380

@@ -1383,15 +1389,15 @@ static LIBDIVIDE_INLINE struct libdivide_s32_t libdivide_internal_s32_gen(
13831389
// This works if works if e < 2**floor_log_2_d.
13841390
if (!branchfree && e < ((uint32_t)1 << floor_log_2_d)) {
13851391
// This power works
1386-
more = floor_log_2_d - 1;
1392+
more = (uint8_t)(floor_log_2_d - 1);
13871393
} else {
13881394
// We need to go one higher. This should not make proposed_m
13891395
// overflow, but it will make it negative when interpreted as an
13901396
// int32_t.
13911397
proposed_m += proposed_m;
13921398
const uint32_t twice_rem = rem + rem;
13931399
if (twice_rem >= absD || twice_rem < rem) proposed_m += 1;
1394-
more = floor_log_2_d | LIBDIVIDE_ADD_MARKER;
1400+
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
13951401
}
13961402

13971403
proposed_m += 1;
@@ -1537,7 +1543,7 @@ static LIBDIVIDE_INLINE struct libdivide_s64_t libdivide_internal_s64_gen(
15371543
if ((absD & (absD - 1)) == 0) {
15381544
// Branchfree and non-branchfree cases are the same
15391545
result.magic = 0;
1540-
result.more = floor_log_2_d | (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0);
1546+
result.more = (uint8_t)(floor_log_2_d | (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0));
15411547
} else {
15421548
// the dividend here is 2**(floor_log_2_d + 63), so the low 64 bit word
15431549
// is 0 and the high word is floor_log_2_d - 1
@@ -1550,7 +1556,7 @@ static LIBDIVIDE_INLINE struct libdivide_s64_t libdivide_internal_s64_gen(
15501556
// This works if works if e < 2**floor_log_2_d.
15511557
if (!branchfree && e < ((uint64_t)1 << floor_log_2_d)) {
15521558
// This power works
1553-
more = floor_log_2_d - 1;
1559+
more = (uint8_t)(floor_log_2_d - 1);
15541560
} else {
15551561
// We need to go one higher. This should not make proposed_m
15561562
// overflow, but it will make it negative when interpreted as an
@@ -1562,7 +1568,7 @@ static LIBDIVIDE_INLINE struct libdivide_s64_t libdivide_internal_s64_gen(
15621568
// also set ADD_MARKER this is an annoying optimization that
15631569
// enables algorithm #4 to avoid the mask. However we always set it
15641570
// in the branchfree case
1565-
more = floor_log_2_d | LIBDIVIDE_ADD_MARKER;
1571+
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
15661572
}
15671573
proposed_m += 1;
15681574
int64_t magic = (int64_t)proposed_m;
@@ -3113,4 +3119,8 @@ using branchfree_divider = divider<T, BRANCHFREE>;
31133119

31143120
#endif // __cplusplus
31153121

3122+
#if defined(_MSC_VER)
3123+
#pragma warning(pop)
3124+
#endif
3125+
31163126
#endif // LIBDIVIDE_H

0 commit comments

Comments
 (0)