From 458c61ae2debbacd7c7d7a427cd0f24a82c99c4e Mon Sep 17 00:00:00 2001 From: gendlin <108626604+gendlin@users.noreply.github.com> Date: Sat, 7 Dec 2024 08:21:34 -0500 Subject: [PATCH] Fix potential overflow in FixedDiv, re-add gcc asm implementation (#1832) * Revert "remove GCC variant of `div64_32` (#1818)" This reverts commit fac7cf789fd9063b523d85dc17b8e6ac701459ae. * Remove asm multi-constraint clang generates poor code otherwise: https://stackoverflow.com/questions/16850309/clang-llvm-inline-assembly-multiple-constraints-with-useless-spills-reload * Fix potential FixedDiv overflow when passed INT_MIN as first arg --- src/m_fixed.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/m_fixed.h b/src/m_fixed.h index 9e740a623..b73dc0180 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -30,6 +30,20 @@ #define div64_32(a, b) _div64((a), (b), NULL) +#elif defined(__GNUC__) && defined(__x86_64__) + + inline static int32_t div64_32(int64_t a, int32_t b) + { + if (__builtin_constant_p(b)) + { + return a / b; + } + int32_t lo = a; + int32_t hi = a >> 32; + asm("idivl %[divisor]" : "+a" (lo), "+d" (hi) : [divisor] "r" (b)); + return lo; + } + #else #define div64_32(a, b) ((fixed_t)((a) / (b))) @@ -72,7 +86,7 @@ inline static int64_t FixedMul64(int64_t a, int64_t b) inline static fixed_t FixedDiv(fixed_t a, fixed_t b) { // [FG] avoid 31-bit shift (from Chocolate Doom) - if ((abs(a) >> 14) >= abs(b)) + if (((unsigned)abs(a) >> 14) >= (unsigned)abs(b)) { return (a ^ b) < 0 ? INT_MIN : INT_MAX; }