Skip to content

Instantly share code, notes, and snippets.

@nickdesaulniers
Created September 10, 2021 21:54
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save nickdesaulniers/2479818f4983bbf2d688cebbab435863 to your computer and use it in GitHub Desktop.
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
*
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