From 5d32f543ecb7f065b1391947a144eb06ca17a854 Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Fri, 6 Aug 2021 18:27:11 +0200 Subject: [PATCH] AK: Handle partial remainders On x86, the `fprem` and `fmprem1` instructions may produce a 'partial remainder', for which we should check by reading a FPU flag. If we don't check for it, we may end up using values that are outside the expected range of values. --- AK/Math.h | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/AK/Math.h b/AK/Math.h index fbaa8901eb8..8424ec8f2f1 100644 --- a/AK/Math.h +++ b/AK/Math.h @@ -65,23 +65,29 @@ template constexpr T fmod(T x, T y) { CONSTEXPR_STATE(fmod, x, y); - T res; - asm( - "fprem" - : "=t"(res) - : "0"(x), "u"(y)); - return res; + u16 fpu_status; + do { + asm( + "fprem\n" + "fnstsw %%ax\n" + : "+t"(x), "=a"(fpu_status) + : "u"(y)); + } while (fpu_status & 0x400); + return x; } template constexpr T remainder(T x, T y) { CONSTEXPR_STATE(remainder, x, y); - T res; - asm( - "fprem1" - : "=t"(res) - : "0"(x), "u"(y)); - return res; + u16 fpu_status; + do { + asm( + "fprem1\n" + "fnstsw %%ax\n" + : "+t"(x), "=a"(fpu_status) + : "u"(y)); + } while (fpu_status & 0x400); + return x; } }