Skip to content

Commit 8ae8f48

Browse files
authored
Simplify how inline math files are included (#1195)
**Issue #:** * #1155 * #1194 Users are reporting double definition of the math inline functions, when building in scenarios I'm not familiar with... The [existing ifdef logic](https://github.com/awslabs/aws-c-common/blob/c6f8f8a3b267e2a2229f71ed0d4b087edd780845/include/aws/common/math.inl#L16-L47) is very hard to follow, so it's not surprising there are edge cases. **Description of changes:** Simplify how inline math files are included - Just have 1 big `#ifdef/elif/elif` chain - If a branch needs 2 .inl files, then include both from from that branch - math.fallback.inl no longer includes math.gcc_builtin.inl in some circumstances. It's the fallback file. Let's keep it simple. - Stop doing the thing where we don't include the .inl files when building `__cplusplus`. - This added too much complexity. Whatever [weird performance edge case](https://github.com/awslabs/aws-c-common/blob/c6f8f8a3b267e2a2229f71ed0d4b087edd780845/include/aws/common/math.inl#L38-L40) we were working around in 2018 is surely fixed in modern compilers.
1 parent c6f8f8a commit 8ae8f48

File tree

5 files changed

+38
-61
lines changed

5 files changed

+38
-61
lines changed

include/aws/common/math.fallback.inl

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ AWS_STATIC_IMPL int aws_add_u32_checked(uint32_t a, uint32_t b, uint32_t *r) {
9494
return AWS_OP_SUCCESS;
9595
}
9696

97-
/*
98-
* These are pure C implementations of the count leading/trailing zeros calls
99-
* They should not be necessary unless using a really esoteric compiler with
100-
* no intrinsics for these functions whatsoever.
101-
*/
102-
#if !defined(__clang__) && !defined(__GNUC__)
10397
/**
10498
* Search from the MSB to LSB, looking for a 1
10599
*/
@@ -144,11 +138,11 @@ AWS_STATIC_IMPL size_t aws_clz_i64(int64_t n) {
144138
}
145139

146140
AWS_STATIC_IMPL size_t aws_clz_size(size_t n) {
147-
# if SIZE_BITS == 64
141+
#if SIZE_BITS == 64
148142
return aws_clz_u64(n);
149-
# else
143+
#else
150144
return aws_clz_u32(n);
151-
# endif
145+
#endif
152146
}
153147

154148
/**
@@ -193,14 +187,12 @@ AWS_STATIC_IMPL size_t aws_ctz_i64(int64_t n) {
193187
}
194188

195189
AWS_STATIC_IMPL size_t aws_ctz_size(size_t n) {
196-
# if SIZE_BITS == 64
190+
#if SIZE_BITS == 64
197191
return aws_ctz_u64(n);
198-
# else
192+
#else
199193
return aws_ctz_u32(n);
200-
# endif
201-
}
202-
203194
#endif
195+
}
204196

205197
AWS_EXTERN_C_END
206198

include/aws/common/math.gcc_arm64_asm.inl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ AWS_STATIC_IMPL int aws_add_u64_checked(uint64_t a, uint64_t b, uint64_t *r) {
109109
uint64_t res, flag;
110110
__asm__("adds %x[res], %x[arga], %x[argb]\n"
111111
"csinv %x[flag], xzr, xzr, cc\n"
112-
: /* inout: res is the result of addition; flag is -1 if carry happened */
112+
: /* inout: res is the result of addition; flag is -1 if carry happened */
113113
[res]"=&r"(res), [flag] "=r"(flag)
114114
: /* in: a and b */ [arga] "r"(a), [argb] "r"(b)
115115
: /* clobbers: cc (cmp clobbers condition codes) */ "cc");

include/aws/common/math.h

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,63 +28,49 @@ AWS_PUSH_SANE_WARNING_LEVEL
2828

2929
AWS_EXTERN_C_BEGIN
3030

31-
#if defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus)) || \
32-
(defined(__x86_64__) || defined(__aarch64__)) && defined(AWS_HAVE_GCC_INLINE_ASM) || \
33-
defined(AWS_HAVE_MSVC_INTRINSICS_X64) || defined(CBMC) || !defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS)
34-
/* In all these cases, we can use fast static inline versions of this code */
35-
# define AWS_COMMON_MATH_API AWS_STATIC_IMPL
36-
#else
37-
/*
38-
* We got here because we are building in C++ mode but we only support overflow extensions
39-
* in C mode. Because the fallback is _slow_ (involving a division), we'd prefer to make a
40-
* non-inline call to the fast C intrinsics.
41-
*/
42-
# define AWS_COMMON_MATH_API AWS_COMMON_API
43-
#endif
44-
4531
/**
4632
* Multiplies a * b. If the result overflows, returns 2^64 - 1.
4733
*/
48-
AWS_COMMON_MATH_API uint64_t aws_mul_u64_saturating(uint64_t a, uint64_t b);
34+
AWS_STATIC_IMPL uint64_t aws_mul_u64_saturating(uint64_t a, uint64_t b);
4935

5036
/**
5137
* If a * b overflows, returns AWS_OP_ERR; otherwise multiplies
5238
* a * b, returns the result in *r, and returns AWS_OP_SUCCESS.
5339
*/
54-
AWS_COMMON_MATH_API int aws_mul_u64_checked(uint64_t a, uint64_t b, uint64_t *r);
40+
AWS_STATIC_IMPL int aws_mul_u64_checked(uint64_t a, uint64_t b, uint64_t *r);
5541

5642
/**
5743
* Multiplies a * b. If the result overflows, returns 2^32 - 1.
5844
*/
59-
AWS_COMMON_MATH_API uint32_t aws_mul_u32_saturating(uint32_t a, uint32_t b);
45+
AWS_STATIC_IMPL uint32_t aws_mul_u32_saturating(uint32_t a, uint32_t b);
6046

6147
/**
6248
* If a * b overflows, returns AWS_OP_ERR; otherwise multiplies
6349
* a * b, returns the result in *r, and returns AWS_OP_SUCCESS.
6450
*/
65-
AWS_COMMON_MATH_API int aws_mul_u32_checked(uint32_t a, uint32_t b, uint32_t *r);
51+
AWS_STATIC_IMPL int aws_mul_u32_checked(uint32_t a, uint32_t b, uint32_t *r);
6652

6753
/**
6854
* Adds a + b. If the result overflows returns 2^64 - 1.
6955
*/
70-
AWS_COMMON_MATH_API uint64_t aws_add_u64_saturating(uint64_t a, uint64_t b);
56+
AWS_STATIC_IMPL uint64_t aws_add_u64_saturating(uint64_t a, uint64_t b);
7157

7258
/**
7359
* If a + b overflows, returns AWS_OP_ERR; otherwise adds
7460
* a + b, returns the result in *r, and returns AWS_OP_SUCCESS.
7561
*/
76-
AWS_COMMON_MATH_API int aws_add_u64_checked(uint64_t a, uint64_t b, uint64_t *r);
62+
AWS_STATIC_IMPL int aws_add_u64_checked(uint64_t a, uint64_t b, uint64_t *r);
7763

7864
/**
7965
* Adds a + b. If the result overflows returns 2^32 - 1.
8066
*/
81-
AWS_COMMON_MATH_API uint32_t aws_add_u32_saturating(uint32_t a, uint32_t b);
67+
AWS_STATIC_IMPL uint32_t aws_add_u32_saturating(uint32_t a, uint32_t b);
8268

8369
/**
8470
* If a + b overflows, returns AWS_OP_ERR; otherwise adds
8571
* a + b, returns the result in *r, and returns AWS_OP_SUCCESS.
8672
*/
87-
AWS_COMMON_MATH_API int aws_add_u32_checked(uint32_t a, uint32_t b, uint32_t *r);
73+
AWS_STATIC_IMPL int aws_add_u32_checked(uint32_t a, uint32_t b, uint32_t *r);
8874

8975
/**
9076
* Subtracts a - b. If the result overflows returns 0.

include/aws/common/math.inl

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,36 @@
1313
#include <limits.h>
1414
#include <stdlib.h>
1515

16-
#if defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus))
17-
/*
18-
* GCC and clang have these super convenient overflow checking builtins...
19-
* but (in the case of GCC) they're only available when building C source.
20-
* We'll fall back to one of the other inlinable variants (or a non-inlined version)
21-
* if we are building this header on G++.
22-
*/
16+
#ifndef __has_builtin
17+
# define __has_builtin(x) 0
18+
#endif
19+
20+
/* CBMC is its own thing */
21+
#if defined(CBMC)
22+
# include <aws/common/math.cbmc.inl>
23+
24+
/* Prefer GCC-style overflow builtins */
25+
#elif defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) || __has_builtin(__builtin_add_overflow)
26+
# include <aws/common/math.gcc_builtin.inl>
2327
# include <aws/common/math.gcc_overflow.inl>
28+
29+
/* Fall back on GCC-style assembly, and ancient builtins available in all versions of GCC and Clang we support */
2430
#elif defined(__x86_64__) && defined(AWS_HAVE_GCC_INLINE_ASM)
31+
# include <aws/common/math.gcc_builtin.inl>
2532
# include <aws/common/math.gcc_x64_asm.inl>
33+
34+
/* Fall back on GCC-style assembly, and ancient builtins available in all versions of GCC and Clang we support */
2635
#elif defined(__aarch64__) && defined(AWS_HAVE_GCC_INLINE_ASM)
2736
# include <aws/common/math.gcc_arm64_asm.inl>
37+
# include <aws/common/math.gcc_builtin.inl>
38+
39+
/* On MSVC, use intrinsics */
2840
#elif defined(AWS_HAVE_MSVC_INTRINSICS_X64)
29-
# include <aws/common/math.msvc.inl>
30-
#elif defined(CBMC)
31-
# include <aws/common/math.cbmc.inl>
32-
#else
33-
# ifndef AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS
34-
/* Fall back to the pure-C implementations */
35-
# include <aws/common/math.fallback.inl>
36-
# else
37-
/*
38-
* We got here because we are building in C++ mode but we only support overflow extensions
39-
* in C mode. Because the fallback is _slow_ (involving a division), we'd prefer to make a
40-
* non-inline call to the fast C intrinsics.
41-
*/
42-
# endif /* AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS */
43-
#endif /* defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus)) */
41+
# include <aws/common/math.msvc_x64.inl>
4442

45-
#if defined(__clang__) || defined(__GNUC__)
46-
# include <aws/common/math.gcc_builtin.inl>
43+
/* Fall back to pure C implementation */
44+
#else
45+
# include <aws/common/math.fallback.inl>
4746
#endif
4847

4948
AWS_EXTERN_C_BEGIN

0 commit comments

Comments
 (0)