├── .github └── workflows │ └── ubuntu.yml ├── .gitignore ├── LICENSE.txt ├── Makefile ├── README.md ├── demo.c ├── demo.sh ├── jtckdint.h ├── test.c └── test.sh /.github/workflows/ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: ubuntu 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: check 17 | run: make check 18 | - name: test 19 | run: ./test.sh 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | /test 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright 2023 Justine Alexandra Roberts Tunney 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 | PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | check: test 2 | ./test 3 | 4 | test: test.o 5 | 6 | test.o: test.c jtckdint.h 7 | 8 | clean: 9 | rm -f test test.o 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C23 Checked Arithmetic 2 | 3 | [jtckdint.h](jtckdint.h) is a portable single-file header-only library 4 | that defines three type generic functions: 5 | 6 | - `bool ckd_add(res, a, b)` 7 | - `bool ckd_sub(res, a, b)` 8 | - `bool ckd_mul(res, a, b)` 9 | 10 | Which allow integer arithmetic errors to be detected. There are many 11 | kinds of integer errors, e.g. overflow, truncation, etc. These funcs 12 | catch them all. Here's an example of how it works: 13 | 14 | ```c 15 | #include "jtckdint.h" 16 | uint32_t c; 17 | int32_t a = 0x7fffffff; 18 | int32_t b = 2; 19 | assert(!ckd_add(&c, a, b)); 20 | assert(c == 0x80000001u); 21 | ``` 22 | 23 | Experienced C / C++ users should find this example counter-intuitive 24 | because the expression `0x7fffffff + 2` not only overflows it's also 25 | undefined behavior. However here we see it's specified, and does not 26 | result in an error. That's because C23 checked arithmetic is not the 27 | arithmetic you're used to. 28 | 29 | C23 checked arithmetic is defined as performing the arithmetic using 30 | infinite precision and then checking if the resulting value will fit 31 | in the output type. Our example above did not result in an error due 32 | to `0x80000001` being a legal value for `uint32_t`. 33 | 34 | This implementation will use the GNU compiler builtins, when they're 35 | available, only if you don't use build flags like `-std=c11` because 36 | they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI. 37 | Instead, you'll get a pretty good pure C11 and C++11 implementation. 38 | 39 | ## Correctness 40 | 41 | Most everyone who's implemented C23 checked arithmetic has gotten it 42 | wrong. Even GNU and Intel have shipped incorrect implementations. We 43 | think we got it right. In [test.c](test.c) you'll find comprehensive 44 | tests of all type combinations which should demonstrate the behavior 45 | of our polyfills is consistent with the GCC/Clang compiler builtins. 46 | You may also run `./test.sh` to test lots of build modes e.g. UBSAN. 47 | 48 | Part of what makes this complicated, is there's a thousand different 49 | possible type combinations. Even when the language has generics that 50 | isn't easy. We make it easy by just promoting everything to intmax_t 51 | which means we only have to perform clever bit hacks when one of the 52 | types is the maximum type. Those hacks are: 53 | 54 | | | z = x + y | z = x - y | z = x * y | 55 | |-------|------------------------------------|------------------------------------|----------------------------------------------| 56 | | u=u∙u | z < x | x < y | x && z / x != y | 57 | | u=u∙s | ((z ^ x) & (z ^ y ^ min)) < 0 | ((x ^ y ^ min) & (z ^ x)) < 0 | x && z / x != y \|\| y < 0 && x | 58 | | u=s∙u | ((z ^ x ^ min) & (z ^ y)) < 0 | y > x \| x < 0 | x && z / x != y \|\| x < 0 && y | 59 | | u=s∙s | ((z \| x) & y \| (z & x) & ~y) < 0 | ((z \| x) & ~y \| (z & x) & y) < 0 | hoo boy | 60 | | s=u∙u | z < x \| z < 0 | x < y ^ z < 0 | x && z / x != y \|\| z < 0 | 61 | | s=u∙s | y ^= min, x + y < y | x >= (y ^ min) | hoo boy | 62 | | s=s∙u | x ^= min, x + y < x | (x ^ min) < y | hoo boy | 63 | | s=s∙s | ((z ^ x) & (z ^ y)) < 0 | ((x ^ y) & (z ^ x)) < 0 | y < 0 && x == min \|\| y && (s)z / (s)y != x | 64 | 65 | These are the best bit hacks I've found, for detecting overflow with 66 | mixed-signedness expressions. The first row is what what you'll find 67 | online with Google. The last row is also commonly known, and easy to 68 | find in books like Hacker's Delight. In the middle is our greenfield 69 | where I've even added my own personal touch. 70 | 71 | ## Quality 72 | 73 | The C11 and C++11 polyfills provided by jtckdint.h generate fabulous 74 | machine code which is in some cases actually better than the builtin 75 | functions provided by your compiler! Here's the output of `demo.sh`, 76 | which can help you compare the quality. 77 | 78 | ``` 79 | ======================================================================== 80 | jtckdint.h using compiler builtins 81 | cc -S -Os -o - demo.c 82 | ======================================================================== 83 | 84 | 85 | ckd_add_unsigned_unsigned_unsigned: 86 | addq %rdx, %rsi 87 | movq %rsi, (%rdi) 88 | setc %al 89 | ret 90 | 91 | ckd_add_signed_signed_signed: 92 | addq %rdx, %rsi 93 | movq %rsi, (%rdi) 94 | seto %al 95 | ret 96 | 97 | ckd_add_unsigned_signed_signed: 98 | xorl %eax, %eax 99 | leaq (%rsi,%rdx), %rcx 100 | testq %rdx, %rdx 101 | js .L10 102 | testq %rcx, %rsi 103 | jmp .L12 104 | .L10: 105 | orq %rcx, %rsi 106 | .L12: 107 | jns .L8 108 | movl $1, %eax 109 | .L8: 110 | movq %rcx, (%rdi) 111 | ret 112 | 113 | ckd_sub_unsigned_unsigned_unsigned: 114 | subq %rdx, %rsi 115 | movq %rsi, (%rdi) 116 | setb %al 117 | ret 118 | 119 | ckd_sub_signed_signed_signed: 120 | subq %rdx, %rsi 121 | movq %rsi, (%rdi) 122 | seto %al 123 | ret 124 | 125 | ckd_sub_unsigned_signed_signed: 126 | movq %rsi, %rcx 127 | xorl %eax, %eax 128 | subq %rdx, %rcx 129 | testq %rdx, %rdx 130 | jns .L23 131 | testq %rcx, %rsi 132 | jmp .L25 133 | .L23: 134 | orq %rcx, %rsi 135 | .L25: 136 | jns .L21 137 | movl $1, %eax 138 | .L21: 139 | movq %rcx, (%rdi) 140 | ret 141 | 142 | ckd_mul_unsigned_unsigned_unsigned: 143 | movq %rsi, %rax 144 | mulq %rdx 145 | movq %rax, (%rdi) 146 | seto %al 147 | ret 148 | 149 | ckd_mul_signed_signed_signed: 150 | imulq %rdx, %rsi 151 | movq %rsi, (%rdi) 152 | seto %al 153 | ret 154 | 155 | ckd_mul_unsigned_signed_signed: 156 | xorl %ecx, %ecx 157 | movq %rsi, %rax 158 | testq %rdx, %rsi 159 | jns .L36 160 | negq %rax 161 | negq %rdx 162 | jmp .L35 163 | .L36: 164 | xorq %rdx, %rsi 165 | jns .L35 166 | testq %rax, %rax 167 | je .L35 168 | xorl %ecx, %ecx 169 | testq %rdx, %rdx 170 | setne %cl 171 | .L35: 172 | mulq %rdx 173 | jno .L33 174 | movl $1, %ecx 175 | .L33: 176 | movq %rax, (%rdi) 177 | movl %ecx, %eax 178 | ret 179 | .ident "GCC: (Alpine 11.2.1_git20220219) 11.2.1 20220219" 180 | 181 | ======================================================================== 182 | jtckdint.h using c11 polyfill 183 | cc -S -Os -std=c11 -o - demo.c 184 | ======================================================================== 185 | 186 | 187 | ckd_add_unsigned_unsigned_unsigned: 188 | addq %rdx, %rsi 189 | movq %rsi, (%rdi) 190 | setc %al 191 | ret 192 | 193 | ckd_add_signed_signed_signed: 194 | leaq (%rdx,%rsi), %rcx 195 | movq %rsi, %rax 196 | xorq %rcx, %rax 197 | xorq %rcx, %rdx 198 | movq %rcx, (%rdi) 199 | andq %rdx, %rax 200 | shrq $63, %rax 201 | ret 202 | 203 | ckd_add_unsigned_signed_signed: 204 | leaq (%rdx,%rsi), %rcx 205 | movq %rsi, %rax 206 | xorq %rcx, %rax 207 | andq %rcx, %rsi 208 | movq %rcx, (%rdi) 209 | andq %rdx, %rax 210 | xorq %rsi, %rax 211 | shrq $63, %rax 212 | ret 213 | 214 | ckd_sub_unsigned_unsigned_unsigned: 215 | movq %rsi, %rax 216 | subq %rdx, %rax 217 | cmpq %rdx, %rsi 218 | movq %rax, (%rdi) 219 | setb %al 220 | ret 221 | 222 | ckd_sub_signed_signed_signed: 223 | movq %rsi, %rcx 224 | movq %rdx, %rax 225 | subq %rdx, %rcx 226 | xorq %rsi, %rax 227 | xorq %rcx, %rsi 228 | movq %rcx, (%rdi) 229 | andq %rsi, %rax 230 | shrq $63, %rax 231 | ret 232 | 233 | ckd_sub_unsigned_signed_signed: 234 | movq %rsi, %rcx 235 | movq %rsi, %rax 236 | subq %rdx, %rcx 237 | xorq %rcx, %rax 238 | orq %rcx, %rsi 239 | movq %rcx, (%rdi) 240 | andq %rdx, %rax 241 | xorq %rsi, %rax 242 | shrq $63, %rax 243 | ret 244 | 245 | ckd_mul_unsigned_unsigned_unsigned: 246 | movq %rsi, %rax 247 | mulq %rdx 248 | movq %rax, (%rdi) 249 | seto %al 250 | ret 251 | 252 | ckd_mul_signed_signed_signed: 253 | movq %rdx, %rax 254 | xorl %ecx, %ecx 255 | imulq %rsi, %rax 256 | movq %rax, (%rdi) 257 | seto %cl 258 | testq %rdx, %rdx 259 | jns .L19 260 | movl $1, %edi 261 | movl $1, %eax 262 | salq $63, %rdi 263 | cmpq %rdi, %rsi 264 | je .L15 265 | .L19: 266 | xorl %eax, %eax 267 | testq %rdx, %rdx 268 | cmovne %ecx, %eax 269 | .L15: 270 | ret 271 | 272 | ckd_mul_unsigned_signed_signed: 273 | movq %rsi, %rax 274 | testq %rsi, %rdx 275 | jns .L23 276 | negq %rax 277 | negq %rdx 278 | xorl %ecx, %ecx 279 | jmp .L24 280 | .L23: 281 | movq %rdx, %rsi 282 | xorl %ecx, %ecx 283 | xorq %rax, %rsi 284 | jns .L24 285 | testq %rax, %rax 286 | setne %sil 287 | xorl %ecx, %ecx 288 | testq %rdx, %rdx 289 | setne %cl 290 | andl %esi, %ecx 291 | .L24: 292 | mulq %rdx 293 | movq %rax, (%rdi) 294 | seto %al 295 | movzbl %al, %eax 296 | orl %ecx, %eax 297 | ret 298 | .ident "GCC: (Alpine 11.2.1_git20220219) 11.2.1 20220219" 299 | 300 | ======================================================================== 301 | jtckdint.h using c++11 polyfill 302 | c++ -S -Os -std=c++11 -xc++ -o - demo.c 303 | ======================================================================== 304 | 305 | 306 | ckd_add_unsigned_unsigned_unsigned: 307 | addq %rdx, %rsi 308 | movq %rsi, (%rdi) 309 | setc %al 310 | ret 311 | 312 | ckd_add_signed_signed_signed: 313 | leaq (%rsi,%rdx), %rcx 314 | movq %rsi, %rax 315 | xorq %rcx, %rax 316 | xorq %rcx, %rdx 317 | movq %rcx, (%rdi) 318 | andq %rdx, %rax 319 | shrq $63, %rax 320 | ret 321 | 322 | ckd_add_unsigned_signed_signed: 323 | leaq (%rsi,%rdx), %rcx 324 | movq %rsi, %rax 325 | xorq %rcx, %rax 326 | andq %rcx, %rsi 327 | movq %rcx, (%rdi) 328 | andq %rdx, %rax 329 | xorq %rsi, %rax 330 | shrq $63, %rax 331 | ret 332 | 333 | ckd_sub_unsigned_unsigned_unsigned: 334 | movq %rsi, %rax 335 | subq %rdx, %rax 336 | cmpq %rdx, %rsi 337 | movq %rax, (%rdi) 338 | setb %al 339 | ret 340 | 341 | ckd_sub_signed_signed_signed: 342 | movq %rsi, %rcx 343 | movq %rdx, %rax 344 | subq %rdx, %rcx 345 | xorq %rsi, %rax 346 | xorq %rcx, %rsi 347 | movq %rcx, (%rdi) 348 | andq %rsi, %rax 349 | shrq $63, %rax 350 | ret 351 | 352 | ckd_sub_unsigned_signed_signed: 353 | movq %rsi, %rcx 354 | movq %rsi, %rax 355 | subq %rdx, %rcx 356 | xorq %rcx, %rax 357 | orq %rcx, %rsi 358 | movq %rcx, (%rdi) 359 | andq %rdx, %rax 360 | xorq %rsi, %rax 361 | shrq $63, %rax 362 | ret 363 | 364 | ckd_mul_unsigned_unsigned_unsigned: 365 | movq %rsi, %rax 366 | mulq %rdx 367 | movq %rax, (%rdi) 368 | seto %al 369 | ret 370 | 371 | ckd_mul_signed_signed_signed: 372 | movq %rsi, %rax 373 | movq %rdi, %r8 374 | xorl %edi, %edi 375 | movq %rdx, %rcx 376 | imulq %rdx, %rax 377 | movq %rax, (%r8) 378 | movl $1, %eax 379 | seto %dil 380 | shrq $63, %rcx 381 | salq $63, %rax 382 | cmpq %rax, %rsi 383 | sete %al 384 | andb %cl, %al 385 | jne .L15 386 | testq %rdx, %rdx 387 | cmovne %edi, %eax 388 | .L15: 389 | ret 390 | 391 | ckd_mul_unsigned_signed_signed: 392 | movq %rdx, %rax 393 | testq %rdx, %rsi 394 | jns .L21 395 | negq %rsi 396 | negq %rax 397 | xorl %ecx, %ecx 398 | jmp .L22 399 | .L21: 400 | movq %rsi, %rdx 401 | xorl %ecx, %ecx 402 | xorq %rax, %rdx 403 | jns .L22 404 | testq %rsi, %rsi 405 | setne %dl 406 | xorl %ecx, %ecx 407 | testq %rax, %rax 408 | setne %cl 409 | andl %edx, %ecx 410 | .L22: 411 | mulq %rsi 412 | movq %rax, (%rdi) 413 | seto %al 414 | movzbl %al, %eax 415 | orl %ecx, %eax 416 | ret 417 | .ident "GCC: (Alpine 11.2.1_git20220219) 11.2.1 20220219" 418 | 419 | ``` 420 | 421 | ## Alternatives 422 | 423 | Consider checking out Kamilcuk's [ckd](https://gitlab.com/Kamcuk/ckd) 424 | library which uses Jinja2 templates to generate an implementation for 425 | each type combination. 426 | 427 | ## See Also 428 | 429 | For further details on checked arithmetic, see the C23 standard: 430 | 431 | 432 | ## Funding 433 | 434 | Funding for our faster, safer integer arithmetic came from: 435 | 436 | - [Mozilla's MIECO program](https://future.mozilla.org/mieco/) 437 | - [jart's GitHub sponsors](https://github.com/sponsors/jart/) 438 | - [jart's Patreon subscribers](https://www.patreon.com/jart) 439 | 440 | Your support is what makes this work possible. Thank you! 441 | -------------------------------------------------------------------------------- /demo.c: -------------------------------------------------------------------------------- 1 | // run ./demo.sh 2 | 3 | #include "jtckdint.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | char ckd_add_unsigned_unsigned_unsigned(unsigned long *z, unsigned long x, unsigned long y) { 10 | return ckd_add(z, x, y); 11 | } 12 | char ckd_add_signed_signed_signed(signed long *z, signed long x, signed long y) { 13 | return ckd_add(z, x, y); 14 | } 15 | char ckd_add_unsigned_signed_signed(unsigned long *z, signed long x, signed long y) { 16 | return ckd_add(z, x, y); 17 | } 18 | 19 | char ckd_sub_unsigned_unsigned_unsigned(unsigned long *z, unsigned long x, unsigned long y) { 20 | return ckd_sub(z, x, y); 21 | } 22 | char ckd_sub_signed_signed_signed(signed long *z, signed long x, signed long y) { 23 | return ckd_sub(z, x, y); 24 | } 25 | char ckd_sub_unsigned_signed_signed(unsigned long *z, signed long x, signed long y) { 26 | return ckd_sub(z, x, y); 27 | } 28 | 29 | char ckd_mul_unsigned_unsigned_unsigned(unsigned long *z, unsigned long x, unsigned long y) { 30 | return ckd_mul(z, x, y); 31 | } 32 | char ckd_mul_signed_signed_signed(signed long *z, signed long x, signed long y) { 33 | return ckd_mul(z, x, y); 34 | } 35 | char ckd_mul_unsigned_signed_signed(unsigned long *z, signed long x, signed long y) { 36 | return ckd_mul(z, x, y); 37 | } 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | filter() { 4 | grep -v cfi | 5 | grep -v \\.file | 6 | grep -v \\.text | 7 | grep -v \\.size | 8 | grep -v \\.type | 9 | grep -v \\.LF | 10 | sed 's/.*\.globl.*//' | 11 | grep -v \\.section 12 | } 13 | 14 | echo 15 | echo ======================================================================== 16 | echo jtckdint.h using compiler builtins 17 | echo cc -S -Os -o - demo.c 18 | echo ======================================================================== 19 | echo 20 | cc -S -Os -o - demo.c | filter 21 | 22 | echo 23 | echo ======================================================================== 24 | echo jtckdint.h using c11 polyfill 25 | echo cc -S -Os -std=c11 -o - demo.c 26 | echo ======================================================================== 27 | echo 28 | cc -S -Os -std=c11 -o - demo.c | filter 29 | 30 | echo 31 | echo ======================================================================== 32 | echo jtckdint.h using c++11 polyfill 33 | echo c++ -S -Os -std=c++11 -xc++ -o - demo.c 34 | echo ======================================================================== 35 | echo 36 | c++ -S -Os -std=c++11 -xc++ -o - demo.c | filter 37 | -------------------------------------------------------------------------------- /jtckdint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Justine Alexandra Roberts Tunney 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for 5 | * any purpose with or without fee is hereby granted, provided that the 6 | * above copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 11 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | * PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | /** 19 | * @fileoverview C23 Checked Arithmetic 20 | * 21 | * This header defines three type generic functions: 22 | * 23 | * - `bool ckd_add(res, a, b)` 24 | * - `bool ckd_sub(res, a, b)` 25 | * - `bool ckd_mul(res, a, b)` 26 | * 27 | * Which allow integer arithmetic errors to be detected. There are many 28 | * kinds of integer errors, e.g. overflow, truncation, etc. These funcs 29 | * catch them all. Here's an example of how it works: 30 | * 31 | * uint32_t c; 32 | * int32_t a = 0x7fffffff; 33 | * int32_t b = 2; 34 | * assert(!ckd_add(&c, a, b)); 35 | * assert(c == 0x80000001u); 36 | * 37 | * Experienced C / C++ users should find this example counter-intuitive 38 | * because the expression `0x7fffffff + 2` not only overflows it's also 39 | * undefined behavior. However here we see it's specified, and does not 40 | * result in an error. That's because C23 checked arithmetic is not the 41 | * arithmetic you're used to. The new standard changes the mathematics. 42 | * 43 | * C23 checked arithmetic is defined as performing the arithmetic using 44 | * infinite precision and then checking if the resulting value will fit 45 | * in the output type. Our example above did not result in an error due 46 | * to `0x80000001` being a legal value for `uint32_t`. 47 | * 48 | * This implementation will use the GNU compiler builtins, when they're 49 | * available, only if you don't use build flags like `-std=c11` because 50 | * they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI. 51 | * Instead, you'll get a pretty good pure C11 and C++11 implementation. 52 | * 53 | * @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf 54 | * @version 1.0 (2024-12-07) 55 | */ 56 | 57 | #ifndef JTCKDINT_H_ 58 | #define JTCKDINT_H_ 59 | 60 | #ifdef __has_include 61 | #define __ckd_has_include(x) __has_include(x) 62 | #else 63 | #define __ckd_has_include(x) 0 64 | #endif 65 | 66 | #if __ckd_has_include() && !defined(__cplusplus) 67 | #include 68 | #else 69 | 70 | #define __STDC_VERSION_STDCKDINT_H__ 202311L 71 | 72 | #if (!defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__)) 73 | #define __ckd_have_int128 74 | #define __ckd_intmax __int128 75 | #elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \ 76 | (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) 77 | #define __ckd_intmax long long 78 | #else 79 | #define __ckd_intmax long 80 | #endif 81 | 82 | typedef signed __ckd_intmax __ckd_intmax_t; 83 | typedef unsigned __ckd_intmax __ckd_uintmax_t; 84 | 85 | #ifdef __has_builtin 86 | #define __ckd_has_builtin(x) __has_builtin(x) 87 | #else 88 | #define __ckd_has_builtin(x) 0 89 | #endif 90 | 91 | #if (!defined(__STRICT_ANSI__) && \ 92 | ((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \ 93 | (__ckd_has_builtin(__builtin_add_overflow) && \ 94 | __ckd_has_builtin(__builtin_sub_overflow) && \ 95 | __ckd_has_builtin(__builtin_mul_overflow)))) 96 | #define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res)) 97 | #define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res)) 98 | #define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res)) 99 | 100 | #elif (defined(__cplusplus) && \ 101 | (__cplusplus >= 201103L || \ 102 | (defined(_MSC_VER) && __cplusplus >= 199711L && \ 103 | __ckd_has_include() && \ 104 | __ckd_has_include()))) 105 | #include 106 | #include 107 | 108 | template 109 | inline bool ckd_add(__T *__res, __U __a, __V __b) { 110 | static_assert(std::is_integral<__T>::value && 111 | std::is_integral<__U>::value && 112 | std::is_integral<__V>::value, 113 | "non-integral types not allowed"); 114 | static_assert(!std::is_same<__T, bool>::value && 115 | !std::is_same<__U, bool>::value && 116 | !std::is_same<__V, bool>::value, 117 | "checked booleans not supported"); 118 | static_assert(!std::is_same<__T, char>::value && 119 | !std::is_same<__U, char>::value && 120 | !std::is_same<__V, char>::value, 121 | "unqualified char type is ambiguous"); 122 | __ckd_uintmax_t __x = __a; 123 | __ckd_uintmax_t __y = __b; 124 | __ckd_uintmax_t __z = __x + __y; 125 | *__res = __z; 126 | if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) { 127 | if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) { 128 | return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z); 129 | } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { 130 | return (__z != static_cast<__T>(__z) || 131 | ((std::is_signed<__U>::value || 132 | std::is_signed<__V>::value) && 133 | static_cast<__ckd_intmax_t>(__z) < 0)); 134 | } 135 | } 136 | bool __truncated = false; 137 | if (sizeof(__T) < sizeof(__ckd_intmax_t)) { 138 | __truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z)); 139 | } 140 | switch (std::is_signed<__T>::value << 2 | // 141 | std::is_signed<__U>::value << 1 | // 142 | std::is_signed<__V>::value) { 143 | case 0: // u = u + u 144 | return __truncated | (__z < __x); 145 | case 1: // u = u + s 146 | __y ^= std::numeric_limits<__ckd_intmax_t>::min(); 147 | return __truncated | 148 | (static_cast<__ckd_intmax_t>((__z ^ __x) & 149 | (__z ^ __y)) < 0); 150 | case 2: // u = s + u 151 | __x ^= std::numeric_limits<__ckd_intmax_t>::min(); 152 | return __truncated | 153 | (static_cast<__ckd_intmax_t>((__z ^ __x) & 154 | (__z ^ __y)) < 0); 155 | case 3: // u = s + s 156 | return __truncated | 157 | (static_cast<__ckd_intmax_t>(((__z | __x) & __y) | 158 | ((__z & __x) & ~__y)) < 0); 159 | case 4: // s = u + u 160 | return __truncated | (__z < __x) | (static_cast<__ckd_intmax_t>(__z) < 0); 161 | case 5: // s = u + s 162 | __y ^= std::numeric_limits<__ckd_intmax_t>::min(); 163 | return __truncated | (__x + __y < __y); 164 | case 6: // s = s + u 165 | __x ^= std::numeric_limits<__ckd_intmax_t>::min(); 166 | return __truncated | (__x + __y < __x); 167 | case 7: // s = s + s 168 | return __truncated | 169 | (static_cast<__ckd_intmax_t>((__z ^ __x) & 170 | (__z ^ __y)) < 0); 171 | default: 172 | for (;;) (void)0; 173 | } 174 | } 175 | 176 | template 177 | inline bool ckd_sub(__T *__res, __U __a, __V __b) { 178 | static_assert(std::is_integral<__T>::value && 179 | std::is_integral<__U>::value && 180 | std::is_integral<__V>::value, 181 | "non-integral types not allowed"); 182 | static_assert(!std::is_same<__T, bool>::value && 183 | !std::is_same<__U, bool>::value && 184 | !std::is_same<__V, bool>::value, 185 | "checked booleans not supported"); 186 | static_assert(!std::is_same<__T, char>::value && 187 | !std::is_same<__U, char>::value && 188 | !std::is_same<__V, char>::value, 189 | "unqualified char type is ambiguous"); 190 | __ckd_uintmax_t __x = __a; 191 | __ckd_uintmax_t __y = __b; 192 | __ckd_uintmax_t __z = __x - __y; 193 | *__res = __z; 194 | bool __truncated = false; 195 | if (sizeof(__T) < sizeof(__ckd_intmax_t)) { 196 | __truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z)); 197 | } 198 | switch (std::is_signed<__T>::value << 2 | // 199 | std::is_signed<__U>::value << 1 | // 200 | std::is_signed<__V>::value) { 201 | case 0: // u = u - u 202 | return __truncated | (__x < __y); 203 | case 1: // u = u - s 204 | __y ^= std::numeric_limits<__ckd_intmax_t>::min(); 205 | return __truncated | 206 | (static_cast<__ckd_intmax_t>((__x ^ __y) & 207 | (__z ^ __x)) < 0); 208 | case 2: // u = s - u 209 | return __truncated | (__y > __x) | (static_cast<__ckd_intmax_t>(__x) < 0); 210 | case 3: // u = s - s 211 | return __truncated | 212 | (static_cast<__ckd_intmax_t>(((__z & __x) & __y) | 213 | ((__z | __x) & ~__y)) < 0); 214 | case 4: // s = u - u 215 | return __truncated | 216 | ((__x < __y) ^ (static_cast<__ckd_intmax_t>(__z) < 0)); 217 | case 5: // s = u - s 218 | __y ^= std::numeric_limits<__ckd_intmax_t>::min(); 219 | return __truncated | (__x >= __y); 220 | case 6: // s = s - u 221 | __x ^= std::numeric_limits<__ckd_intmax_t>::min(); 222 | return __truncated | (__x < __y); 223 | case 7: // s = s - s 224 | return __truncated | 225 | (static_cast<__ckd_intmax_t>((__x ^ __y) & 226 | (__z ^ __x)) < 0); 227 | default: 228 | for (;;) (void)0; 229 | } 230 | } 231 | 232 | template 233 | inline bool ckd_mul(__T *__res, __U __a, __V __b) { 234 | static_assert(std::is_integral<__T>::value && 235 | std::is_integral<__U>::value && 236 | std::is_integral<__V>::value, 237 | "non-integral types not allowed"); 238 | static_assert(!std::is_same<__T, bool>::value && 239 | !std::is_same<__U, bool>::value && 240 | !std::is_same<__V, bool>::value, 241 | "checked booleans not supported"); 242 | static_assert(!std::is_same<__T, char>::value && 243 | !std::is_same<__U, char>::value && 244 | !std::is_same<__V, char>::value, 245 | "unqualified char type is ambiguous"); 246 | __ckd_uintmax_t __x = __a; 247 | __ckd_uintmax_t __y = __b; 248 | if ((sizeof(__U) * 8 - std::is_signed<__U>::value) + 249 | (sizeof(__V) * 8 - std::is_signed<__V>::value) <= 250 | (sizeof(__T) * 8 - std::is_signed<__T>::value)) { 251 | if (sizeof(__ckd_uintmax_t) > sizeof(__T) || std::is_signed<__T>::value) { 252 | __ckd_intmax_t __z = __x * __y; 253 | return __z != (*__res = __z); 254 | } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { 255 | __ckd_uintmax_t __z = __x * __y; 256 | *__res = __z; 257 | return (__z != static_cast<__T>(__z) || 258 | ((std::is_signed<__U>::value || 259 | std::is_signed<__V>::value) && 260 | static_cast<__ckd_intmax_t>(__z) < 0)); 261 | } 262 | } 263 | switch (std::is_signed<__T>::value << 2 | // 264 | std::is_signed<__U>::value << 1 | // 265 | std::is_signed<__V>::value) { 266 | case 0: { // u = u * u 267 | __ckd_uintmax_t __z = __x * __y; 268 | int __o = __x && __z / __x != __y; 269 | *__res = __z; 270 | return __o | (sizeof(__T) < sizeof(__z) && 271 | __z != static_cast<__ckd_uintmax_t>(*__res)); 272 | } 273 | case 1: { // u = u * s 274 | __ckd_uintmax_t __z = __x * __y; 275 | int __o = __x && __z / __x != __y; 276 | *__res = __z; 277 | return (__o | ((static_cast<__ckd_intmax_t>(__y) < 0) & !!__x) | 278 | (sizeof(__T) < sizeof(__z) && 279 | __z != static_cast<__ckd_uintmax_t>(*__res))); 280 | } 281 | case 2: { // u = s * u 282 | __ckd_uintmax_t __z = __x * __y; 283 | int __o = __x && __z / __x != __y; 284 | *__res = __z; 285 | return (__o | ((static_cast<__ckd_intmax_t>(__x) < 0) & !!__y) | 286 | (sizeof(__T) < sizeof(__z) && 287 | __z != static_cast<__ckd_uintmax_t>(*__res))); 288 | } 289 | case 3: { // u = s * s 290 | int __o = false; 291 | if (static_cast<__ckd_intmax_t>(__x & __y) < 0) { 292 | __x = 0 - __x; 293 | __y = 0 - __y; 294 | } else if (static_cast<__ckd_intmax_t>(__x ^ __y) < 0) { 295 | __o = __x && __y; 296 | } 297 | __ckd_uintmax_t __z = __x * __y; 298 | __o |= __x && __z / __x != __y; 299 | *__res = __z; 300 | return __o | (sizeof(__T) < sizeof(__z) && 301 | __z != static_cast<__ckd_uintmax_t>(*__res)); 302 | } 303 | case 4: { // s = u * u 304 | __ckd_uintmax_t __z = __x * __y; 305 | int __o = __x && __z / __x != __y; 306 | *__res = __z; 307 | return (__o | (static_cast<__ckd_intmax_t>(__z) < 0) | 308 | (sizeof(__T) < sizeof(__z) && 309 | __z != static_cast<__ckd_uintmax_t>(*__res))); 310 | } 311 | case 5: { // s = u * s 312 | __ckd_uintmax_t __t = 0 - __y; 313 | __t = static_cast<__ckd_intmax_t>(__t) < 0 ? __y : __t; 314 | __ckd_uintmax_t __p = __t * __x; 315 | int __o = __t && __p / __t != __x; 316 | int __n = static_cast<__ckd_intmax_t>(__y) < 0; 317 | __ckd_uintmax_t __z = __n ? 0 - __p : __p; 318 | *__res = __z; 319 | __ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max(); 320 | return (__o | (__p > __m + __n) | 321 | (sizeof(__T) < sizeof(__z) && 322 | __z != static_cast<__ckd_uintmax_t>(*__res))); 323 | } 324 | case 6: { // s = s * u 325 | __ckd_uintmax_t __t = 0 - __x; 326 | __t = static_cast<__ckd_intmax_t>(__t) < 0 ? __x : __t; 327 | __ckd_uintmax_t __p = __t * __y; 328 | int __o = __t && __p / __t != __y; 329 | int __n = static_cast<__ckd_intmax_t>(__x) < 0; 330 | __ckd_uintmax_t __z = __n ? 0 - __p : __p; 331 | *__res = __z; 332 | __ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max(); 333 | return (__o | (__p > __m + __n) | 334 | (sizeof(__T) < sizeof(__z) && 335 | __z != static_cast<__ckd_uintmax_t>(*__res))); 336 | } 337 | case 7: { // s = s * s 338 | __ckd_uintmax_t __z = __x * __y; 339 | *__res = __z; 340 | return ((((static_cast<__ckd_intmax_t>(__y) < 0) && 341 | (static_cast<__ckd_intmax_t>(__x) == 342 | std::numeric_limits<__ckd_intmax_t>::min())) || 343 | (__y && ((static_cast<__ckd_intmax_t>(__z) / 344 | static_cast<__ckd_intmax_t>(__y)) != 345 | static_cast<__ckd_intmax_t>(__x)))) | 346 | (sizeof(__T) < sizeof(__z) && 347 | __z != static_cast<__ckd_uintmax_t>(*__res))); 348 | } 349 | default: 350 | for (;;) (void)0; 351 | } 352 | } 353 | 354 | #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L 355 | 356 | #define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b)) 357 | #define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b)) 358 | #define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b)) 359 | 360 | #if defined(__GNUC__) || defined(__llvm__) 361 | #define __ckd_inline \ 362 | extern __inline __attribute__((__gnu_inline__, \ 363 | __always_inline__, \ 364 | __artificial__)) 365 | #else 366 | #define __ckd_inline static inline 367 | #endif 368 | 369 | #ifdef __ckd_have_int128 370 | #define __ckd_generic_int128(x, y) , signed __int128: x, unsigned __int128: y 371 | #else 372 | #define __ckd_generic_int128(x, y) 373 | #endif 374 | 375 | #define __ckd_sign(T) \ 376 | ((T)1 << (sizeof(T) * 8 - 1)) 377 | 378 | #define __ckd_is_signed(x) \ 379 | _Generic(x, \ 380 | signed char: 1, \ 381 | unsigned char: 0, \ 382 | signed short: 1, \ 383 | unsigned short: 0, \ 384 | signed int: 1, \ 385 | unsigned int: 0, \ 386 | signed long: 1, \ 387 | unsigned long: 0, \ 388 | signed long long: 1, \ 389 | unsigned long long: 0 \ 390 | __ckd_generic_int128(1, 0)) 391 | 392 | #define __ckd_expr(op, res, a, b) \ 393 | (_Generic(*res, \ 394 | signed char: __ckd_##op##_schar, \ 395 | unsigned char: __ckd_##op##_uchar, \ 396 | signed short: __ckd_##op##_sshort, \ 397 | unsigned short: __ckd_##op##_ushort, \ 398 | signed int: __ckd_##op##_sint, \ 399 | unsigned int: __ckd_##op##_uint, \ 400 | signed long: __ckd_##op##_slong, \ 401 | unsigned long: __ckd_##op##_ulong, \ 402 | signed long long: __ckd_##op##_slonger, \ 403 | unsigned long long: __ckd_##op##_ulonger \ 404 | __ckd_generic_int128( \ 405 | __ckd_##op##_sint128, \ 406 | __ckd_##op##_uint128))( \ 407 | res, a, b, \ 408 | __ckd_is_signed(a), \ 409 | __ckd_is_signed(b))) 410 | 411 | #define __ckd_declare_add(S, T) \ 412 | __ckd_inline char S(void *__res, \ 413 | __ckd_uintmax_t __x, \ 414 | __ckd_uintmax_t __y, \ 415 | char __a_signed, \ 416 | char __b_signed) { \ 417 | __ckd_uintmax_t __z = __x + __y; \ 418 | *(T *)__res = __z; \ 419 | char __truncated = 0; \ 420 | if (sizeof(T) < sizeof(__ckd_intmax_t)) { \ 421 | __truncated = __z != (__ckd_uintmax_t)(T)__z; \ 422 | } \ 423 | switch (__ckd_is_signed((T)0) << 2 | \ 424 | __a_signed << 1 | __b_signed) { \ 425 | case 0: /* u = u + u */ \ 426 | return __truncated | (__z < __x); \ 427 | case 1: /* u = u + s */ \ 428 | __y ^= __ckd_sign(__ckd_uintmax_t); \ 429 | return __truncated | \ 430 | ((__ckd_intmax_t)((__z ^ __x) & \ 431 | (__z ^ __y)) < 0); \ 432 | case 2: /* u = s + u */ \ 433 | __x ^= __ckd_sign(__ckd_uintmax_t); \ 434 | return __truncated | \ 435 | ((__ckd_intmax_t)((__z ^ __x) & \ 436 | (__z ^ __y)) < 0); \ 437 | case 3: /* u = s + s */ \ 438 | return __truncated | \ 439 | ((__ckd_intmax_t)(((__z | __x) & __y) | \ 440 | ((__z & __x) & ~__y)) < 0); \ 441 | case 4: /* s = u + u */ \ 442 | return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \ 443 | case 5: /* s = u + s */ \ 444 | __y ^= __ckd_sign(__ckd_uintmax_t); \ 445 | return __truncated | (__x + __y < __y); \ 446 | case 6: /* s = s + u */ \ 447 | __x ^= __ckd_sign(__ckd_uintmax_t); \ 448 | return __truncated | (__x + __y < __x); \ 449 | case 7: /* s = s + s */ \ 450 | return __truncated | \ 451 | ((__ckd_intmax_t)((__z ^ __x) & \ 452 | (__z ^ __y)) < 0); \ 453 | default: \ 454 | for (;;) (void)0; \ 455 | } \ 456 | } 457 | 458 | __ckd_declare_add(__ckd_add_schar, signed char) 459 | __ckd_declare_add(__ckd_add_uchar, unsigned char) 460 | __ckd_declare_add(__ckd_add_sshort, signed short) 461 | __ckd_declare_add(__ckd_add_ushort, unsigned short) 462 | __ckd_declare_add(__ckd_add_sint, signed int) 463 | __ckd_declare_add(__ckd_add_uint, unsigned int) 464 | __ckd_declare_add(__ckd_add_slong, signed long) 465 | __ckd_declare_add(__ckd_add_ulong, unsigned long) 466 | __ckd_declare_add(__ckd_add_slonger, signed long long) 467 | __ckd_declare_add(__ckd_add_ulonger, unsigned long long) 468 | #ifdef __ckd_have_int128 469 | __ckd_declare_add(__ckd_add_sint128, signed __int128) 470 | __ckd_declare_add(__ckd_add_uint128, unsigned __int128) 471 | #endif 472 | 473 | #define __ckd_declare_sub(S, T) \ 474 | __ckd_inline char S(void *__res, \ 475 | __ckd_uintmax_t __x, \ 476 | __ckd_uintmax_t __y, \ 477 | char __a_signed, \ 478 | char __b_signed) { \ 479 | __ckd_uintmax_t __z = __x - __y; \ 480 | *(T *)__res = __z; \ 481 | char __truncated = 0; \ 482 | if (sizeof(T) < sizeof(__ckd_intmax_t)) { \ 483 | __truncated = __z != (__ckd_uintmax_t)(T)__z; \ 484 | } \ 485 | switch (__ckd_is_signed((T)0) << 2 | \ 486 | __a_signed << 1 | __b_signed) { \ 487 | case 0: /* u = u - u */ \ 488 | return __truncated | (__x < __y); \ 489 | case 1: /* u = u - s */ \ 490 | __y ^= __ckd_sign(__ckd_uintmax_t); \ 491 | return __truncated | \ 492 | ((__ckd_intmax_t)((__x ^ __y) & \ 493 | (__z ^ __x)) < 0); \ 494 | case 2: /* u = s - u */ \ 495 | return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \ 496 | case 3: /* u = s - s */ \ 497 | return __truncated | \ 498 | ((__ckd_intmax_t)(((__z & __x) & __y) | \ 499 | ((__z | __x) & ~__y)) < 0); \ 500 | case 4: /* s = u - u */ \ 501 | return __truncated | ((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \ 502 | case 5: /* s = u - s */ \ 503 | __y ^= __ckd_sign(__ckd_uintmax_t); \ 504 | return __truncated | (__x >= __y); \ 505 | case 6: /* s = s - u */ \ 506 | __x ^= __ckd_sign(__ckd_uintmax_t); \ 507 | return __truncated | (__x < __y); \ 508 | case 7: /* s = s - s */ \ 509 | return __truncated | \ 510 | ((__ckd_intmax_t)((__x ^ __y) & \ 511 | (__z ^ __x)) < 0); \ 512 | default: \ 513 | for (;;) (void)0; \ 514 | } \ 515 | } 516 | 517 | __ckd_declare_sub(__ckd_sub_schar, signed char) 518 | __ckd_declare_sub(__ckd_sub_uchar, unsigned char) 519 | __ckd_declare_sub(__ckd_sub_sshort, signed short) 520 | __ckd_declare_sub(__ckd_sub_ushort, unsigned short) 521 | __ckd_declare_sub(__ckd_sub_sint, signed int) 522 | __ckd_declare_sub(__ckd_sub_uint, unsigned int) 523 | __ckd_declare_sub(__ckd_sub_slong, signed long) 524 | __ckd_declare_sub(__ckd_sub_ulong, unsigned long) 525 | __ckd_declare_sub(__ckd_sub_slonger, signed long long) 526 | __ckd_declare_sub(__ckd_sub_ulonger, unsigned long long) 527 | #ifdef __ckd_have_int128 528 | __ckd_declare_sub(__ckd_sub_sint128, signed __int128) 529 | __ckd_declare_sub(__ckd_sub_uint128, unsigned __int128) 530 | #endif 531 | 532 | #define __ckd_declare_mul(S, T) \ 533 | __ckd_inline char S(void *__res, \ 534 | __ckd_uintmax_t __x, \ 535 | __ckd_uintmax_t __y, \ 536 | char __a_signed, \ 537 | char __b_signed) { \ 538 | switch (__ckd_is_signed((T)0) << 2 | \ 539 | __a_signed << 1 | __b_signed) { \ 540 | case 0: { /* u = u * u */ \ 541 | __ckd_uintmax_t __z = __x * __y; \ 542 | int __o = __x && __z / __x != __y; \ 543 | *(T *)__res = __z; \ 544 | return __o | (sizeof(T) < sizeof(__z) && \ 545 | __z != (__ckd_uintmax_t)*(T *)__res); \ 546 | } \ 547 | case 1: { /* u = u * s */ \ 548 | __ckd_uintmax_t __z = __x * __y; \ 549 | int __o = __x && __z / __x != __y; \ 550 | *(T *)__res = __z; \ 551 | return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \ 552 | (sizeof(T) < sizeof(__z) && \ 553 | __z != (__ckd_uintmax_t)*(T *)__res)); \ 554 | } \ 555 | case 2: { /* u = s * u */ \ 556 | __ckd_uintmax_t __z = __x * __y; \ 557 | int __o = __x && __z / __x != __y; \ 558 | *(T *)__res = __z; \ 559 | return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \ 560 | (sizeof(T) < sizeof(__z) && \ 561 | __z != (__ckd_uintmax_t)*(T *)__res)); \ 562 | } \ 563 | case 3: { /* u = s * s */ \ 564 | int __o = 0; \ 565 | if ((__ckd_intmax_t)(__x & __y) < 0) { \ 566 | __x = 0 - __x; \ 567 | __y = 0 - __y; \ 568 | } else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \ 569 | __o = __x && __y; \ 570 | } \ 571 | __ckd_uintmax_t __z = __x * __y; \ 572 | __o |= __x && __z / __x != __y; \ 573 | *(T *)__res = __z; \ 574 | return __o | (sizeof(T) < sizeof(__z) && \ 575 | __z != (__ckd_uintmax_t)*(T *)__res); \ 576 | } \ 577 | case 4: { /* s = u * u */ \ 578 | __ckd_uintmax_t __z = __x * __y; \ 579 | int __o = __x && __z / __x != __y; \ 580 | *(T *)__res = __z; \ 581 | return (__o | ((__ckd_intmax_t)(__z) < 0) | \ 582 | (sizeof(T) < sizeof(__z) && \ 583 | __z != (__ckd_uintmax_t)*(T *)__res)); \ 584 | } \ 585 | case 5: { /* s = u * s */ \ 586 | __ckd_uintmax_t __t = 0 - __y; \ 587 | __t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \ 588 | __ckd_uintmax_t __p = __t * __x; \ 589 | int __o = __t && __p / __t != __x; \ 590 | int __n = (__ckd_intmax_t)__y < 0; \ 591 | __ckd_uintmax_t __z = __n ? 0 - __p : __p; \ 592 | *(T *)__res = __z; \ 593 | __ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \ 594 | return (__o | (__p > __m + __n) | \ 595 | (sizeof(T) < sizeof(__z) && \ 596 | __z != (__ckd_uintmax_t)*(T *)__res)); \ 597 | } \ 598 | case 6: { /* s = s * u */ \ 599 | __ckd_uintmax_t __t = 0 - __x; \ 600 | __t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \ 601 | __ckd_uintmax_t __p = __t * __y; \ 602 | int __o = __t && __p / __t != __y; \ 603 | int __n = (__ckd_intmax_t)__x < 0; \ 604 | __ckd_uintmax_t __z = __n ? 0 - __p : __p; \ 605 | *(T *)__res = __z; \ 606 | __ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \ 607 | return (__o | (__p > __m + __n) | \ 608 | (sizeof(T) < sizeof(__z) && \ 609 | __z != (__ckd_uintmax_t)*(T *)__res)); \ 610 | } \ 611 | case 7: { /* s = s * s */ \ 612 | __ckd_uintmax_t __z = __x * __y; \ 613 | *(T *)__res = __z; \ 614 | return (((((__ckd_intmax_t)__y < 0) && \ 615 | (__x == __ckd_sign(__ckd_uintmax_t))) || \ 616 | (__y && (((__ckd_intmax_t)__z / \ 617 | (__ckd_intmax_t)__y) != \ 618 | (__ckd_intmax_t)__x))) | \ 619 | (sizeof(T) < sizeof(__z) && \ 620 | __z != (__ckd_uintmax_t)*(T *)__res)); \ 621 | } \ 622 | default: \ 623 | for (;;) (void)0; \ 624 | } \ 625 | } 626 | 627 | __ckd_declare_mul(__ckd_mul_schar, signed char) 628 | __ckd_declare_mul(__ckd_mul_uchar, unsigned char) 629 | __ckd_declare_mul(__ckd_mul_sshort, signed short) 630 | __ckd_declare_mul(__ckd_mul_ushort, unsigned short) 631 | __ckd_declare_mul(__ckd_mul_sint, signed int) 632 | __ckd_declare_mul(__ckd_mul_uint, unsigned int) 633 | __ckd_declare_mul(__ckd_mul_slong, signed long) 634 | __ckd_declare_mul(__ckd_mul_ulong, unsigned long) 635 | __ckd_declare_mul(__ckd_mul_slonger, signed long long) 636 | __ckd_declare_mul(__ckd_mul_ulonger, unsigned long long) 637 | #ifdef __ckd_have_int128 638 | __ckd_declare_mul(__ckd_mul_sint128, signed __int128) 639 | __ckd_declare_mul(__ckd_mul_uint128, unsigned __int128) 640 | #endif 641 | 642 | #else 643 | #pragma message "checked integer arithmetic unsupported in this environment" 644 | 645 | #define ckd_add(res, x, y) (*(res) = (x) + (y), 0) 646 | #define ckd_sub(res, x, y) (*(res) = (x) - (y), 0) 647 | #define ckd_mul(res, x, y) (*(res) = (x) * (y), 0) 648 | 649 | #endif /* GNU */ 650 | #endif /* stdckdint.h */ 651 | #endif /* JTCKDINT_H_ */ 652 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Justine Alexandra Roberts Tunney 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for 4 | // any purpose with or without fee is hereby granted, provided that the 5 | // above copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 8 | // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 9 | // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 10 | // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 11 | // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 12 | // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 13 | // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | // PERFORMANCE OF THIS SOFTWARE. 15 | 16 | #include "jtckdint.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef __ckd_intmax 24 | 25 | #define TBIT(T) (sizeof(T) * 8 - 1) 26 | #define TMIN(T) (((T) ~(T)0) > 1 ? (T)0 : (T)((__ckd_uintmax_t)1 << TBIT(T))) 27 | #define TMAX(T) (((T) ~(T)0) > 1 ? (T) ~(T)0 : (T)(((__ckd_uintmax_t)1 << TBIT(T)) - 1)) 28 | 29 | #ifdef __ckd_have_int128 30 | typedef signed __int128 int128_t; 31 | typedef unsigned __int128 uint128_t; 32 | #endif 33 | 34 | #define DECLARE_TEST_VECTORS(T) \ 35 | static const T k##T[] = { \ 36 | 0, 1, 2, 3, 4, 5, 6, \ 37 | (T)-1, (T)-2, (T)-3, (T)-4, (T)-5, (T)-6, \ 38 | TMIN(T), \ 39 | (T)(TMIN(T) + 1), \ 40 | (T)(TMIN(T) + 2), \ 41 | (T)(TMIN(T) + 3), \ 42 | (T)(TMIN(T) + 4), \ 43 | TMAX(T), \ 44 | (T)(TMAX(T) - 1), \ 45 | (T)(TMAX(T) - 2), \ 46 | (T)(TMAX(T) - 3), \ 47 | (T)(TMAX(T) - 4), \ 48 | (T)(TMIN(T) / 2), \ 49 | (T)(TMIN(T) / 2 + 1), \ 50 | (T)(TMIN(T) / 2 + 2), \ 51 | (T)(TMIN(T) / 2 + 3), \ 52 | (T)(TMIN(T) / 2 + 4), \ 53 | (T)(TMAX(T) / 2), \ 54 | (T)(TMAX(T) / 2 - 1), \ 55 | (T)(TMAX(T) / 2 - 2), \ 56 | (T)(TMAX(T) / 2 - 3), \ 57 | (T)(TMAX(T) / 2 - 4), \ 58 | } 59 | 60 | DECLARE_TEST_VECTORS(int8_t); 61 | DECLARE_TEST_VECTORS(uint8_t); 62 | DECLARE_TEST_VECTORS(int16_t); 63 | DECLARE_TEST_VECTORS(uint16_t); 64 | DECLARE_TEST_VECTORS(int32_t); 65 | DECLARE_TEST_VECTORS(uint32_t); 66 | DECLARE_TEST_VECTORS(int64_t); 67 | DECLARE_TEST_VECTORS(uint64_t); 68 | #ifdef __ckd_have_int128 69 | DECLARE_TEST_VECTORS(int128_t); 70 | DECLARE_TEST_VECTORS(uint128_t); 71 | #endif 72 | 73 | int main(int argc, char *argv[]) { 74 | (void)argc; 75 | (void)argv; 76 | 77 | #define M(T,U,V) \ 78 | for (unsigned i = 0; i < sizeof(k##U) / sizeof(k##U[0]); ++i) { \ 79 | U x = k##U[i]; \ 80 | for (unsigned j = 0; j < sizeof(k##V) / sizeof(k##V[0]); ++j) { \ 81 | T z1, z2; \ 82 | V y = k##V[j]; \ 83 | assert(ckd_add(&z1, x, y) == __builtin_add_overflow(x, y, &z2)); \ 84 | assert(z1 == z2); \ 85 | assert(ckd_sub(&z1, x, y) == __builtin_sub_overflow(x, y, &z2)); \ 86 | assert(z1 == z2); \ 87 | assert(ckd_mul(&z1, x, y) == __builtin_mul_overflow(x, y, &z2)); \ 88 | assert(z1 == z2); \ 89 | } \ 90 | } 91 | 92 | #ifdef __ckd_have_int128 93 | #define MM(T, U) \ 94 | M(T, U, uint8_t) \ 95 | M(T, U, uint16_t) \ 96 | M(T, U, uint32_t) \ 97 | M(T, U, uint64_t) \ 98 | M(T, U, uint128_t) \ 99 | M(T, U, int8_t) \ 100 | M(T, U, int16_t) \ 101 | M(T, U, int32_t) \ 102 | M(T, U, int64_t) \ 103 | M(T, U, int128_t) 104 | #define MMM(T) \ 105 | MM(T, uint8_t) \ 106 | MM(T, uint16_t) \ 107 | MM(T, uint32_t) \ 108 | MM(T, uint64_t) \ 109 | MM(T, uint128_t) \ 110 | MM(T, int8_t) \ 111 | MM(T, int16_t) \ 112 | MM(T, int32_t) \ 113 | MM(T, int64_t) \ 114 | MM(T, int128_t) 115 | MMM(uint8_t) 116 | MMM(uint16_t) 117 | MMM(uint32_t) 118 | MMM(uint64_t) 119 | MMM(uint128_t) 120 | MMM(int8_t) 121 | MMM(int16_t) 122 | MMM(int32_t) 123 | MMM(int64_t) 124 | MMM(int128_t) 125 | 126 | #else 127 | #define MM(T, U) \ 128 | M(T, U, uint8_t) \ 129 | M(T, U, uint16_t) \ 130 | M(T, U, uint32_t) \ 131 | M(T, U, uint64_t) \ 132 | M(T, U, int8_t) \ 133 | M(T, U, int16_t) \ 134 | M(T, U, int32_t) \ 135 | M(T, U, int64_t) 136 | #define MMM(T) \ 137 | MM(T, uint8_t) \ 138 | MM(T, uint16_t) \ 139 | MM(T, uint32_t) \ 140 | MM(T, uint64_t) \ 141 | MM(T, int8_t) \ 142 | MM(T, int16_t) \ 143 | MM(T, int32_t) \ 144 | MM(T, int64_t) 145 | MMM(uint8_t) 146 | MMM(uint16_t) 147 | MMM(uint32_t) 148 | MMM(uint64_t) 149 | MMM(int8_t) 150 | MMM(int16_t) 151 | MMM(int32_t) 152 | MMM(int64_t) 153 | #endif 154 | 155 | } 156 | 157 | #else 158 | int main(int argc, char *argv[]) { 159 | (void)argc; 160 | (void)argv; 161 | } 162 | #endif 163 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | for cc in clang cc; do 5 | for opt in -O0 -O3 -fsanitize=undefined; do 6 | make clean 7 | make CC="$cc -Wall -Wextra -Werror $opt" 8 | make clean 9 | make CC="$cc -Wall -Wextra -Werror -pedantic-errors $opt -std=c11" 10 | done 11 | done 12 | 13 | for cc in c++ clang++; do 14 | for opt in -O0 -O3 -fsanitize=undefined; do 15 | make clean 16 | make CC="$cc -Wall -Wextra -Werror $opt" CFLAGS="-xc++" 17 | make clean 18 | make CC="$cc -Wall -Wextra -Werror -pedantic-errors $opt -std=c++11" CFLAGS="-xc++" 19 | done 20 | done 21 | 22 | make clean 23 | make 24 | --------------------------------------------------------------------------------