summaryrefslogtreecommitdiff
path: root/src/include/common
diff options
context:
space:
mode:
authorNathan Bossart2024-08-15 20:47:31 +0000
committerNathan Bossart2024-08-15 20:47:31 +0000
commit9e9a2b7031f64e49fcaf28f21a4e70eb1212165f (patch)
treee7abac509a29b705ad76d8d5123894fe3e1bf3ba /src/include/common
parentad89d71978429c61647ae57174a61deb192bd51c (diff)
Remove dependence on -fwrapv semantics in a few places.
This commit attempts to update a few places, such as the money, numeric, and timestamp types, to no longer rely on signed integer wrapping for correctness. This is intended to move us closer towards removing -fwrapv, which may enable some compiler optimizations. However, there is presently no plan to actually remove that compiler option in the near future. Besides using some of the existing overflow-aware routines in int.h, this commit introduces and makes use of some new ones. Specifically, it adds functions that accept a signed integer and return its absolute value as an unsigned integer with the same width (e.g., pg_abs_s64()). It also adds functions that accept an unsigned integer, store the result of negating that integer in a signed integer with the same width, and return whether the negation overflowed (e.g., pg_neg_u64_overflow()). Finally, this commit adds a couple of tests for timestamps near POSTGRES_EPOCH_JDATE. Author: Joseph Koshakow Reviewed-by: Tom Lane, Heikki Linnakangas, Jian He Discussion: https://postgr.es/m/CAAvxfHdBPOyEGS7s%2Bxf4iaW0-cgiq25jpYdWBqQqvLtLe_t6tw%40mail.gmail.com
Diffstat (limited to 'src/include/common')
-rw-r--r--src/include/common/int.h131
1 files changed, 123 insertions, 8 deletions
diff --git a/src/include/common/int.h b/src/include/common/int.h
index 7fc046e78af..3b1590d676f 100644
--- a/src/include/common/int.h
+++ b/src/include/common/int.h
@@ -23,15 +23,35 @@
/*---------
* The following guidelines apply to all the overflow routines:
- * - If a + b overflows, return true, otherwise store the result of a + b
- * into *result. The content of *result is implementation defined in case of
- * overflow.
- * - If a - b overflows, return true, otherwise store the result of a - b
- * into *result. The content of *result is implementation defined in case of
- * overflow.
- * - If a * b overflows, return true, otherwise store the result of a * b
- * into *result. The content of *result is implementation defined in case of
+ *
+ * If the result overflows, return true, otherwise store the result into
+ * *result. The content of *result is implementation defined in case of
* overflow.
+ *
+ * bool pg_add_*_overflow(a, b, *result)
+ *
+ * Calculate a + b
+ *
+ * bool pg_sub_*_overflow(a, b, *result)
+ *
+ * Calculate a - b
+ *
+ * bool pg_mul_*_overflow(a, b, *result)
+ *
+ * Calculate a * b
+ *
+ * bool pg_neg_*_overflow(a, *result)
+ *
+ * Calculate -a
+ *
+ *
+ * In addition, this file contains:
+ *
+ * <unsigned int type> pg_abs_*(<signed int type> a)
+ *
+ * Calculate absolute value of a. Unlike the standard library abs()
+ * and labs() functions, the return type is unsigned, so the operation
+ * cannot overflow.
*---------
*/
@@ -97,6 +117,17 @@ pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
#endif
}
+static inline uint16
+pg_abs_s16(int16 a)
+{
+ /*
+ * This first widens the argument from int16 to int32 for use with abs().
+ * The result is then narrowed from int32 to uint16. This prevents any
+ * possibility of overflow.
+ */
+ return (uint16) abs((int32) a);
+}
+
/*
* INT32
*/
@@ -154,6 +185,17 @@ pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
#endif
}
+static inline uint32
+pg_abs_s32(int32 a)
+{
+ /*
+ * This first widens the argument from int32 to int64 for use with
+ * i64abs(). The result is then narrowed from int64 to uint32. This
+ * prevents any possibility of overflow.
+ */
+ return (uint32) i64abs((int64) a);
+}
+
/*
* INT64
*/
@@ -258,6 +300,14 @@ pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
#endif
}
+static inline uint64
+pg_abs_s64(int64 a)
+{
+ if (unlikely(a == PG_INT64_MIN))
+ return (uint64) PG_INT64_MAX + 1;
+ return (uint64) i64abs(a);
+}
+
/*------------------------------------------------------------------------
* Overflow routines for unsigned integers
*------------------------------------------------------------------------
@@ -318,6 +368,24 @@ pg_mul_u16_overflow(uint16 a, uint16 b, uint16 *result)
#endif
}
+static inline bool
+pg_neg_u16_overflow(uint16 a, int16 *result)
+{
+#if defined(HAVE__BUILTIN_OP_OVERFLOW)
+ return __builtin_sub_overflow(0, a, result);
+#else
+ int32 res = -((int32) a);
+
+ if (unlikely(res < PG_INT16_MIN))
+ {
+ *result = 0x5EED; /* to avoid spurious warnings */
+ return true;
+ }
+ *result = res;
+ return false;
+#endif
+}
+
/*
* INT32
*/
@@ -373,6 +441,24 @@ pg_mul_u32_overflow(uint32 a, uint32 b, uint32 *result)
#endif
}
+static inline bool
+pg_neg_u32_overflow(uint32 a, int32 *result)
+{
+#if defined(HAVE__BUILTIN_OP_OVERFLOW)
+ return __builtin_sub_overflow(0, a, result);
+#else
+ int64 res = -((int64) a);
+
+ if (unlikely(res < PG_INT32_MIN))
+ {
+ *result = 0x5EED; /* to avoid spurious warnings */
+ return true;
+ }
+ *result = res;
+ return false;
+#endif
+}
+
/*
* UINT64
*/
@@ -438,6 +524,35 @@ pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result)
#endif
}
+static inline bool
+pg_neg_u64_overflow(uint64 a, int64 *result)
+{
+#if defined(HAVE__BUILTIN_OP_OVERFLOW)
+ return __builtin_sub_overflow(0, a, result);
+#elif defined(HAVE_INT128)
+ int128 res = -((int128) a);
+
+ if (unlikely(res < PG_INT64_MIN))
+ {
+ *result = 0x5EED; /* to avoid spurious warnings */
+ return true;
+ }
+ *result = res;
+ return false;
+#else
+ if (unlikely(a > (uint64) PG_INT64_MAX + 1))
+ {
+ *result = 0x5EED; /* to avoid spurious warnings */
+ return true;
+ }
+ if (unlikely(a == (uint64) PG_INT64_MAX + 1))
+ *result = PG_INT64_MIN;
+ else
+ *result = -((int64) a);
+ return false;
+#endif
+}
+
/*------------------------------------------------------------------------
*
* Comparison routines for integer types.