Created
September 10, 2021 21:54
Star
You must be signed in to star a gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/linux/math64.h b/include/linux/math64.h | |
index 2928f03d6d46..989b094663c0 100644 | |
--- a/include/linux/math64.h | |
+++ b/include/linux/math64.h | |
@@ -11,6 +11,9 @@ | |
#define div64_long(x, y) div64_s64((x), (y)) | |
#define div64_ul(x, y) div64_u64((x), (y)) | |
+#ifndef is_signed_type | |
+#define is_signed_type(type) (((type)(-1)) < (type)1) | |
+#endif | |
/** | |
* div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder | |
@@ -112,6 +115,18 @@ extern s64 div64_s64(s64 dividend, s64 divisor); | |
#endif /* BITS_PER_LONG */ | |
+// perhaps too strict, since we can promote y to s64 | |
+ //static_assert(__builtin_types_compatible_p(typeof(x), s64) || __builtin_types_compatible_p(typeof(x), u64)); | |
+#define div64_x64(dividend, divisor) ({ \ | |
+ typeof(dividend) z; \ | |
+ BUILD_BUG_ON_MSG(!__builtin_types_compatible_p(typeof(divisor), s64) && !__builtin_types_compatible_p(typeof(divisor), u64), "prefer div_x64"); \ | |
+ if(is_signed_type(typeof(dividend))) \ | |
+ z = div64_s64(dividend, divisor); \ | |
+ else \ | |
+ z = div64_u64(dividend, divisor); \ | |
+ z; \ | |
+}) | |
+ | |
/** | |
* div_u64 - unsigned 64bit divide with 32bit divisor | |
* @dividend: unsigned 64bit dividend | |
@@ -142,6 +157,30 @@ static inline s64 div_s64(s64 dividend, s32 divisor) | |
} | |
#endif | |
+#define div_x64(dividend, divisor) ({ \ | |
+ typeof(dividend) z; \ | |
+ if(is_signed_type(typeof(dividend))) \ | |
+ z = div_s64(dividend, divisor); \ | |
+ else \ | |
+ z = div_u64(dividend, divisor); \ | |
+ z; \ | |
+}) | |
+ | |
+// TODO: what if divisor is 128b? | |
+#define div_64(dividend, divisor) ({ \ | |
+ typeof(dividend) z; \ | |
+ if (__builtin_types_compatible_p(typeof(dividend), s64) || \ | |
+ __builtin_types_compatible_p(typeof(dividend), u64)) { \ | |
+ if (__builtin_types_compatible_p(typeof(divisor), s64) || \ | |
+ __builtin_types_compatible_p(typeof(divisor), u64)) \ | |
+ z = div64_x64(dividend, divisor); \ | |
+ else \ | |
+ z = div_x64(dividend, divisor); \ | |
+ } else \ | |
+ z = dividend / divisor; \ | |
+ z; \ | |
+}) | |
+ | |
u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder); | |
#ifndef mul_u32_u32 | |
diff --git a/include/linux/overflow.h b/include/linux/overflow.h | |
index 0f12345c21fb..bbbeddaaf28c 100644 | |
--- a/include/linux/overflow.h | |
+++ b/include/linux/overflow.h | |
@@ -4,6 +4,7 @@ | |
#include <linux/compiler.h> | |
#include <linux/limits.h> | |
+#include <linux/math64.h> | |
/* | |
* In the fallback code below, we need to compute the minimum and | |
@@ -81,15 +82,6 @@ static inline bool __must_check __must_check_overflow(bool overflow) | |
__builtin_sub_overflow(__a, __b, __d); \ | |
})) | |
-#define check_mul_overflow(a, b, d) __must_check_overflow(({ \ | |
- typeof(a) __a = (a); \ | |
- typeof(b) __b = (b); \ | |
- typeof(d) __d = (d); \ | |
- (void) (&__a == &__b); \ | |
- (void) (&__a == __d); \ | |
- __builtin_mul_overflow(__a, __b, __d); \ | |
-})) | |
- | |
#else | |
@@ -112,21 +104,6 @@ static inline bool __must_check __must_check_overflow(bool overflow) | |
*__d = __a - __b; \ | |
__a < __b; \ | |
}) | |
-/* | |
- * If one of a or b is a compile-time constant, this avoids a division. | |
- */ | |
-#define __unsigned_mul_overflow(a, b, d) ({ \ | |
- typeof(a) __a = (a); \ | |
- typeof(b) __b = (b); \ | |
- typeof(d) __d = (d); \ | |
- (void) (&__a == &__b); \ | |
- (void) (&__a == __d); \ | |
- *__d = __a * __b; \ | |
- __builtin_constant_p(__b) ? \ | |
- __b > 0 && __a > type_max(typeof(__a)) / __b : \ | |
- __a > 0 && __b > type_max(typeof(__b)) / __a; \ | |
-}) | |
- | |
/* | |
* For signed types, detecting overflow is much harder, especially if | |
* we want to avoid UB. But the interface of these macros is such that | |
@@ -170,6 +147,32 @@ static inline bool __must_check __must_check_overflow(bool overflow) | |
& type_min(typeof(__a))) != 0; \ | |
}) | |
+ | |
+#define check_add_overflow(a, b, d) __must_check_overflow( \ | |
+ __builtin_choose_expr(is_signed_type(typeof(a)), \ | |
+ __signed_add_overflow(a, b, d), \ | |
+ __unsigned_add_overflow(a, b, d))) | |
+ | |
+#define check_sub_overflow(a, b, d) __must_check_overflow( \ | |
+ __builtin_choose_expr(is_signed_type(typeof(a)), \ | |
+ __signed_sub_overflow(a, b, d), \ | |
+ __unsigned_sub_overflow(a, b, d))) | |
+ | |
+#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ | |
+/* | |
+ * If one of a or b is a compile-time constant, this avoids a division. | |
+ */ | |
+#define __unsigned_mul_overflow(a, b, d) ({ \ | |
+ typeof(a) __a = (a); \ | |
+ typeof(b) __b = (b); \ | |
+ typeof(d) __d = (d); \ | |
+ (void) (&__a == &__b); \ | |
+ (void) (&__a == __d); \ | |
+ *__d = __a * __b; \ | |
+ __builtin_constant_p(__b) ? \ | |
+ __b > 0 && __a > type_max(typeof(__a)) / __b : \ | |
+ __a > 0 && __b > type_max(typeof(__b)) / __a; \ | |
+}) | |
/* | |
* Signed multiplication is rather hard. gcc always follows C99, so | |
* division is truncated towards 0. This means that we can write the | |
@@ -195,28 +198,17 @@ static inline bool __must_check __must_check_overflow(bool overflow) | |
(void) (&__a == &__b); \ | |
(void) (&__a == __d); \ | |
*__d = (u64)__a * (u64)__b; \ | |
- (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \ | |
- (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \ | |
+ (__b > 0 && (__a > div_64(__tmax, __b) || __a < div_64(__tmin, __b))) || \ | |
+ (__b < (typeof(__b))-1 && (__a > div_64(__tmin, __b) || __a < div_64(__tmax, __b))) || \ | |
(__b == (typeof(__b))-1 && __a == __tmin); \ | |
}) | |
- | |
- | |
-#define check_add_overflow(a, b, d) __must_check_overflow( \ | |
- __builtin_choose_expr(is_signed_type(typeof(a)), \ | |
- __signed_add_overflow(a, b, d), \ | |
- __unsigned_add_overflow(a, b, d))) | |
- | |
-#define check_sub_overflow(a, b, d) __must_check_overflow( \ | |
- __builtin_choose_expr(is_signed_type(typeof(a)), \ | |
- __signed_sub_overflow(a, b, d), \ | |
- __unsigned_sub_overflow(a, b, d))) | |
- | |
#define check_mul_overflow(a, b, d) __must_check_overflow( \ | |
__builtin_choose_expr(is_signed_type(typeof(a)), \ | |
__signed_mul_overflow(a, b, d), \ | |
__unsigned_mul_overflow(a, b, d))) | |
-#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ | |
+ | |
+ | |
/** check_shl_overflow() - Calculate a left-shifted value and check overflow | |
* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fad7cd3310db3099f95dd34312c77740fbc455e5 | |
exposed | |
https://lore.kernel.org/all/20210909182525.372ee687@canb.auug.org.au/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment