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
This commit is contained in:
gendlin 2024-12-07 08:21:34 -05:00 committed by GitHub
parent 89aae9c789
commit 458c61ae2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -30,6 +30,20 @@
#define div64_32(a, b) _div64((a), (b), NULL) #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 #else
#define div64_32(a, b) ((fixed_t)((a) / (b))) #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) inline static fixed_t FixedDiv(fixed_t a, fixed_t b)
{ {
// [FG] avoid 31-bit shift (from Chocolate Doom) // [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; return (a ^ b) < 0 ? INT_MIN : INT_MAX;
} }