diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,11 @@
 # Changelog for rounded-hw
 
+## 0.4.0 (2023-11-18)
+
+* Disable `x87-long-double` flag by default.
+* Support GHC 9.4 to 9.8 (inclusive).
+* Fix `roundedMul` of `ViaRational`.
+
 ## 0.3.0 (2022-01-08)
 
 * Support Clang on AArch64.
diff --git a/benchmark/Benchmark.hs b/benchmark/Benchmark.hs
--- a/benchmark/Benchmark.hs
+++ b/benchmark/Benchmark.hs
@@ -11,13 +11,13 @@
 import           Data.Ratio
 import qualified Data.Vector as V
 import qualified Data.Vector.Unboxed as VU
-import           Gauge.Main
 import           IGA
 import           Numeric.Rounded.Hardware.Internal
 import           Numeric.Rounded.Hardware.Interval
 import           Numeric.Rounded.Hardware.Interval.Class (makeInterval)
 import qualified Numeric.Rounded.Hardware.Interval.NonEmpty as NE
 import qualified Numeric.Rounded.Hardware.Vector.Unboxed as RVU
+import           Test.Tasty.Bench
 
 foreign import ccall unsafe "fma"
   c_fma_double :: Double -> Double -> Double -> Double
diff --git a/benchmark/Conversion.hs b/benchmark/Conversion.hs
--- a/benchmark/Conversion.hs
+++ b/benchmark/Conversion.hs
@@ -8,13 +8,13 @@
 import           Data.Int
 import           Data.Ratio
 import           Data.Word
-import           Gauge.Benchmark
 import           Numeric.Floating.IEEE
 import qualified Numeric.Floating.IEEE.Internal as IEEE.Internal
 import           Numeric.Rounded.Hardware
 import qualified Numeric.Rounded.Hardware.Backend.C as C
 import           Numeric.Rounded.Hardware.Class
 import           Numeric.Rounded.Hardware.Interval
+import           Test.Tasty.Bench
 
 word64ToDouble :: RoundingMode -> Word64 -> Double
 word64ToDouble ToNearest x
diff --git a/benchmark/IGA.hs b/benchmark/IGA.hs
--- a/benchmark/IGA.hs
+++ b/benchmark/IGA.hs
@@ -12,9 +12,9 @@
 import qualified Data.Vector.Mutable as VM
 import qualified Data.Vector.Unboxed as VU
 import qualified Data.Vector.Unboxed.Mutable as VUM
-import           Gauge.Benchmark
 import           Numeric.Rounded.Hardware.Interval
 import qualified Numeric.Rounded.Hardware.Interval.NonEmpty as NE
+import           Test.Tasty.Bench
 
 thawST :: (Ix i, IArray a e) => a i e -> ST s (STArray s i e)
 thawST = thaw
diff --git a/cbits/rounded-common.inl b/cbits/rounded-common.inl
--- a/cbits/rounded-common.inl
+++ b/cbits/rounded-common.inl
@@ -4,11 +4,14 @@
 // double
 //
 
-static inline double rounded_add_impl_double(native_rounding_mode mode, double a, double b)
+static inline double rounded_add_impl_double(native_rounding_mode mode, VOLATILE double a, VOLATILE double b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double c = a + b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE double c = a + b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -21,11 +24,14 @@
 extern double rounded_hw_add_double_zero(double a, double b)
 { return rounded_add_impl_double(ROUND_TOWARDZERO, a, b); }
 
-static inline double rounded_sub_impl_double(native_rounding_mode mode, double a, double b)
+static inline double rounded_sub_impl_double(native_rounding_mode mode, VOLATILE double a, VOLATILE double b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double c = a - b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE double c = a - b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -38,11 +44,14 @@
 extern double rounded_hw_sub_double_zero(double a, double b)
 { return rounded_sub_impl_double(ROUND_TOWARDZERO, a, b); }
 
-static inline double rounded_mul_impl_double(native_rounding_mode mode, double a, double b)
+static inline double rounded_mul_impl_double(native_rounding_mode mode, VOLATILE double a, VOLATILE double b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double c = a * b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE double c = a * b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -55,11 +64,14 @@
 extern double rounded_hw_mul_double_zero(double a, double b)
 { return rounded_mul_impl_double(ROUND_TOWARDZERO, a, b); }
 
-static inline double rounded_div_impl_double(native_rounding_mode mode, double a, double b)
+static inline double rounded_div_impl_double(native_rounding_mode mode, VOLATILE double a, VOLATILE double b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double c = a / b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE double c = a / b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -72,11 +84,19 @@
 extern double rounded_hw_div_double_zero(double a, double b)
 { return rounded_div_impl_double(ROUND_TOWARDZERO, a, b); }
 
-static inline double rounded_sqrt_impl_double(native_rounding_mode mode, double a)
+static inline double rounded_sqrt_impl_double(native_rounding_mode mode, VOLATILE double a)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double c = sqrt(a);
+#if defined(__GNUC__) && defined(USE_SSE2)
+    // mingw-w64's sqrt may use x87 instead of SSE2
+    double c;
+    __asm__ volatile("sqrtsd %1, %0" : "=x"(c) : "x"(a));
+#else
+    MAY_MODIFY(a);
+    VOLATILE double c = sqrt(a);
+    FORCE_EVAL(c);
+#endif
     restore_fp_reg(oldreg);
     return c;
 }
@@ -89,11 +109,15 @@
 extern double rounded_hw_sqrt_double_zero(double a)
 { return rounded_sqrt_impl_double(ROUND_TOWARDZERO, a); }
 
-static inline double rounded_fma_impl_double(native_rounding_mode mode, double a, double b, double c)
+static inline double rounded_fma_impl_double(native_rounding_mode mode, VOLATILE double a, VOLATILE double b, VOLATILE double c)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double result = fma(a, b, c);
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    MAY_MODIFY(c);
+    VOLATILE double result = fma(a, b, c);
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -106,15 +130,19 @@
 extern double rounded_hw_fma_double_zero(double a, double b, double c)
 { return rounded_fma_impl_double(ROUND_TOWARDZERO, a, b, c); }
 
-static inline double rounded_fma_if_fast_impl_double(native_rounding_mode mode, double a, double b, double c)
+static inline double rounded_fma_if_fast_impl_double(native_rounding_mode mode, VOLATILE double a, VOLATILE double b, VOLATILE double c)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    MAY_MODIFY(c);
 #ifdef FP_FAST_FMA
-    volatile double result = fma(a, b, c);
+    VOLATILE double result = fma(a, b, c);
 #else
-    volatile double result = a * b + c;
+    VOLATILE double result = a * b + c;
 #endif
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -135,7 +163,8 @@
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double result = (double)x;
+    VOLATILE double result = (double)x;
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -152,7 +181,8 @@
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile double result = (double)x;
+    VOLATILE double result = (double)x;
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -188,138 +218,182 @@
     return fast_fmin_double(fast_fmin_double(x, y), fast_fmin_double(z, w));
 }
 
-extern double rounded_hw_interval_mul_double_up(double lo1, double hi1, double lo2, double hi2)
+extern double rounded_hw_interval_mul_double_up(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    double x = (volatile double)(lo1 * lo2);
-    double y = (volatile double)(lo1 * hi2);
-    double z = (volatile double)(hi1 * lo2);
-    double w = (volatile double)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    VOLATILE double x = lo1 * lo2;
+    VOLATILE double y = lo1 * hi2;
+    VOLATILE double z = hi1 * lo2;
+    VOLATILE double w = hi1 * hi2;
     if (isnan(x)) x = 0.0; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 * inf -> 0 */
-    double hi = fast_fmax4_double(x, y, z, w);
+    VOLATILE double hi = fast_fmax4_double(x, y, z, w);
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern double rounded_hw_interval_mul_double_down(double lo1, double hi1, double lo2, double hi2)
+extern double rounded_hw_interval_mul_double_down(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    double x = (volatile double)(lo1 * lo2);
-    double y = (volatile double)(lo1 * hi2);
-    double z = (volatile double)(hi1 * lo2);
-    double w = (volatile double)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    VOLATILE double x = lo1 * lo2;
+    VOLATILE double y = lo1 * hi2;
+    VOLATILE double z = hi1 * lo2;
+    VOLATILE double w = hi1 * hi2;
     if (isnan(x)) x = 0.0; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 * inf -> 0 */
-    double lo = fast_fmin4_double(x, y, z, w);
+    VOLATILE double lo = fast_fmin4_double(x, y, z, w);
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
 
-extern double rounded_hw_interval_mul_add_double_up(double lo1, double hi1, double lo2, double hi2, double hi3)
+extern double rounded_hw_interval_mul_add_double_up(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2, VOLATILE double hi3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    double x = (volatile double)(lo1 * lo2);
-    double y = (volatile double)(lo1 * hi2);
-    double z = (volatile double)(hi1 * lo2);
-    double w = (volatile double)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(hi3);
+    double x = lo1 * lo2;
+    double y = lo1 * hi2;
+    double z = hi1 * lo2;
+    double w = hi1 * hi2;
     if (isnan(x)) x = 0.0; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 * inf -> 0 */
-    volatile double hi = fast_fmax4_double(x, y, z, w) + hi3;
+    VOLATILE double hi = fast_fmax4_double(x, y, z, w) + hi3;
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern double rounded_hw_interval_mul_add_double_down(double lo1, double hi1, double lo2, double hi2, double lo3)
+extern double rounded_hw_interval_mul_add_double_down(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2, VOLATILE double lo3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    double x = (volatile double)(lo1 * lo2);
-    double y = (volatile double)(lo1 * hi2);
-    double z = (volatile double)(hi1 * lo2);
-    double w = (volatile double)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(lo3);
+    double x = lo1 * lo2;
+    double y = lo1 * hi2;
+    double z = hi1 * lo2;
+    double w = hi1 * hi2;
     if (isnan(x)) x = 0.0; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 * inf -> 0 */
-    volatile double lo = fast_fmin4_double(x, y, z, w) + lo3;
+    VOLATILE double lo = fast_fmin4_double(x, y, z, w) + lo3;
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
 
-extern double rounded_hw_interval_div_double_up(double lo1, double hi1, double lo2, double hi2)
+extern double rounded_hw_interval_div_double_up(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    double x = (volatile double)(lo1 / lo2);
-    double y = (volatile double)(lo1 / hi2);
-    double z = (volatile double)(hi1 / lo2);
-    double w = (volatile double)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    double x = lo1 / lo2;
+    double y = lo1 / hi2;
+    double z = hi1 / lo2;
+    double w = hi1 / hi2;
     if (isnan(x)) x = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
-    double hi = fast_fmax4_double(x, y, z, w);
+    VOLATILE double hi = fast_fmax4_double(x, y, z, w);
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern double rounded_hw_interval_div_double_down(double lo1, double hi1, double lo2, double hi2)
+extern double rounded_hw_interval_div_double_down(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    double x = (volatile double)(lo1 / lo2);
-    double y = (volatile double)(lo1 / hi2);
-    double z = (volatile double)(hi1 / lo2);
-    double w = (volatile double)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    double x = lo1 / lo2;
+    double y = lo1 / hi2;
+    double z = hi1 / lo2;
+    double w = hi1 / hi2;
     if (isnan(x)) x = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
-    double lo = fast_fmin4_double(x, y, z, w);
+    VOLATILE double lo = fast_fmin4_double(x, y, z, w);
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
 
-extern double rounded_hw_interval_div_add_double_up(double lo1, double hi1, double lo2, double hi2, double hi3)
+extern double rounded_hw_interval_div_add_double_up(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2, VOLATILE double hi3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    double x = (volatile double)(lo1 / lo2);
-    double y = (volatile double)(lo1 / hi2);
-    double z = (volatile double)(hi1 / lo2);
-    double w = (volatile double)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(hi3);
+    double x = lo1 / lo2;
+    double y = lo1 / hi2;
+    double z = hi1 / lo2;
+    double w = hi1 / hi2;
     if (isnan(x)) x = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
-    volatile double hi = fast_fmax4_double(x, y, z, w) + hi3;
+    VOLATILE double hi = fast_fmax4_double(x, y, z, w) + hi3;
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern double rounded_hw_interval_div_add_double_down(double lo1, double hi1, double lo2, double hi2, double lo3)
+extern double rounded_hw_interval_div_add_double_down(VOLATILE double lo1, VOLATILE double hi1, VOLATILE double lo2, VOLATILE double hi2, VOLATILE double lo3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    double x = (volatile double)(lo1 / lo2);
-    double y = (volatile double)(lo1 / hi2);
-    double z = (volatile double)(hi1 / lo2);
-    double w = (volatile double)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(lo3);
+    double x = lo1 / lo2;
+    double y = lo1 / hi2;
+    double z = hi1 / lo2;
+    double w = hi1 / hi2;
     if (isnan(x)) x = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0; /* 0 / 0, +-inf / +-inf -> 0 */
-    volatile double lo = fast_fmin4_double(x, y, z, w) + lo3;
+    VOLATILE double lo = fast_fmin4_double(x, y, z, w) + lo3;
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
@@ -333,10 +407,12 @@
     native_rounding_mode nmode = hs_rounding_mode_to_native(mode);
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, nmode);
-    volatile double s = 0.0;
+    VOLATILE double s = 0.0;
+    MAY_MODIFY(s);
     for (HsInt i = 0; i < length; ++i) {
         s += a[offset + i];
     }
+    FORCE_EVAL(s);
     restore_fp_reg(oldreg);
     return s;
 }
@@ -401,9 +477,25 @@
     native_rounding_mode nmode = hs_rounding_mode_to_native(mode);
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, nmode);
+#if defined(__GNUC__) && defined(USE_SSE2)
+    // mingw-w64's sqrt may use x87 instead of SSE2
+    HsInt i = 0;
+    for (; i + 2 <= length; i += 2) {
+        __m128d aa = _mm_loadu_pd(&a[offsetA + i]);
+        __m128d bb = _mm_sqrt_pd(aa);
+        _mm_storeu_pd(&result[offsetR + i], bb);
+    }
+    for (; i < length; ++i) {
+        double aa = a[offsetA + i];
+        double bb;
+        __asm__ volatile("sqrtsd %1, %0" : "=x"(bb) : "x"(aa));
+        result[offsetR + i] = bb;
+    }
+#else
     for (HsInt i = 0; i < length; ++i) {
         result[offsetR + i] = sqrt(a[offsetA + i]);
     }
+#endif
     restore_fp_reg(oldreg);
 }
 
@@ -411,11 +503,14 @@
 // float
 //
 
-static inline float rounded_add_impl_float(native_rounding_mode mode, float a, float b)
+static inline float rounded_add_impl_float(native_rounding_mode mode, VOLATILE float a, VOLATILE float b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float c = a + b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE float c = a + b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -428,11 +523,14 @@
 extern float rounded_hw_add_float_zero(float a, float b)
 { return rounded_add_impl_float(ROUND_TOWARDZERO, a, b); }
 
-static inline float rounded_sub_impl_float(native_rounding_mode mode, float a, float b)
+static inline float rounded_sub_impl_float(native_rounding_mode mode, VOLATILE float a, VOLATILE float b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float c = a - b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE float c = a - b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -445,11 +543,14 @@
 extern float rounded_hw_sub_float_zero(float a, float b)
 { return rounded_sub_impl_float(ROUND_TOWARDZERO, a, b); }
 
-static inline float rounded_mul_impl_float(native_rounding_mode mode, float a, float b)
+static inline float rounded_mul_impl_float(native_rounding_mode mode, VOLATILE float a, VOLATILE float b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float c = a * b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE float c = a * b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -462,11 +563,14 @@
 extern float rounded_hw_mul_float_zero(float a, float b)
 { return rounded_mul_impl_float(ROUND_TOWARDZERO, a, b); }
 
-static inline float rounded_div_impl_float(native_rounding_mode mode, float a, float b)
+static inline float rounded_div_impl_float(native_rounding_mode mode, VOLATILE float a, VOLATILE float b)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float c = a / b;
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    VOLATILE float c = a / b;
+    FORCE_EVAL(c);
     restore_fp_reg(oldreg);
     return c;
 }
@@ -479,11 +583,19 @@
 extern float rounded_hw_div_float_zero(float a, float b)
 { return rounded_div_impl_float(ROUND_TOWARDZERO, a, b); }
 
-static inline float rounded_sqrt_impl_float(native_rounding_mode mode, float a)
+static inline float rounded_sqrt_impl_float(native_rounding_mode mode, VOLATILE float a)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float c = sqrtf(a);
+#if defined(__GNUC__) && defined(USE_SSE2)
+    // mingw-w64's sqrtf may use x87 instead of SSE2
+    float c;
+    __asm__ volatile("sqrtss %1, %0" : "=x"(c) : "x"(a));
+#else
+    MAY_MODIFY(a);
+    VOLATILE float c = sqrtf(a);
+    FORCE_EVAL(c);
+#endif
     restore_fp_reg(oldreg);
     return c;
 }
@@ -496,11 +608,15 @@
 extern float rounded_hw_sqrt_float_zero(float a)
 { return rounded_sqrt_impl_float(ROUND_TOWARDZERO, a); }
 
-static inline float rounded_fma_impl_float(native_rounding_mode mode, float a, float b, float c)
+static inline float rounded_fma_impl_float(native_rounding_mode mode, VOLATILE float a, VOLATILE float b, VOLATILE float c)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float result = fmaf(a, b, c);
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    MAY_MODIFY(c);
+    VOLATILE float result = fmaf(a, b, c);
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -513,15 +629,19 @@
 extern float rounded_hw_fma_float_zero(float a, float b, float c)
 { return rounded_fma_impl_float(ROUND_TOWARDZERO, a, b, c); }
 
-static inline float rounded_fma_if_fast_impl_float(native_rounding_mode mode, float a, float b, float c)
+static inline float rounded_fma_if_fast_impl_float(native_rounding_mode mode, VOLATILE float a, VOLATILE float b, VOLATILE float c)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
+    MAY_MODIFY(a);
+    MAY_MODIFY(b);
+    MAY_MODIFY(c);
 #ifdef FP_FAST_FMAF
-    volatile float result = fmaf(a, b, c);
+    VOLATILE float result = fmaf(a, b, c);
 #else
-    volatile float result = a * b + c;
+    VOLATILE float result = a * b + c;
 #endif
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -542,7 +662,8 @@
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float result = (float)x;
+    VOLATILE float result = (float)x;
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -559,7 +680,8 @@
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, mode);
-    volatile float result = (float)x;
+    VOLATILE float result = (float)x;
+    FORCE_EVAL(result);
     restore_fp_reg(oldreg);
     return result;
 }
@@ -595,138 +717,182 @@
     return fast_fmin_float(fast_fmin_float(x, y), fast_fmin_float(z, w));
 }
 
-extern float rounded_hw_interval_mul_float_up(float lo1, float hi1, float lo2, float hi2)
+extern float rounded_hw_interval_mul_float_up(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    float x = (volatile float)(lo1 * lo2);
-    float y = (volatile float)(lo1 * hi2);
-    float z = (volatile float)(hi1 * lo2);
-    float w = (volatile float)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    VOLATILE float x = lo1 * lo2;
+    VOLATILE float y = lo1 * hi2;
+    VOLATILE float z = hi1 * lo2;
+    VOLATILE float w = hi1 * hi2;
     if (isnan(x)) x = 0.0f; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 * inf -> 0 */
-    float hi = fast_fmax4_float(x, y, z, w);
+    VOLATILE float hi = fast_fmax4_float(x, y, z, w);
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern float rounded_hw_interval_mul_float_down(float lo1, float hi1, float lo2, float hi2)
+extern float rounded_hw_interval_mul_float_down(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    float x = (volatile float)(lo1 * lo2);
-    float y = (volatile float)(lo1 * hi2);
-    float z = (volatile float)(hi1 * lo2);
-    float w = (volatile float)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    VOLATILE float x = lo1 * lo2;
+    VOLATILE float y = lo1 * hi2;
+    VOLATILE float z = hi1 * lo2;
+    VOLATILE float w = hi1 * hi2;
     if (isnan(x)) x = 0.0f; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 * inf -> 0 */
-    float lo = fast_fmin4_float(x, y, z, w);
+    VOLATILE float lo = fast_fmin4_float(x, y, z, w);
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
 
-extern float rounded_hw_interval_mul_add_float_up(float lo1, float hi1, float lo2, float hi2, float hi3)
+extern float rounded_hw_interval_mul_add_float_up(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2, VOLATILE float hi3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    float x = (volatile float)(lo1 * lo2);
-    float y = (volatile float)(lo1 * hi2);
-    float z = (volatile float)(hi1 * lo2);
-    float w = (volatile float)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(hi3);
+    float x = lo1 * lo2;
+    float y = lo1 * hi2;
+    float z = hi1 * lo2;
+    float w = hi1 * hi2;
     if (isnan(x)) x = 0.0f; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 * inf -> 0 */
-    volatile float hi = fast_fmax4_float(x, y, z, w) + hi3;
+    VOLATILE float hi = fast_fmax4_float(x, y, z, w) + hi3;
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern float rounded_hw_interval_mul_add_float_down(float lo1, float hi1, float lo2, float hi2, float lo3)
+extern float rounded_hw_interval_mul_add_float_down(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2, VOLATILE float lo3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    float x = (volatile float)(lo1 * lo2);
-    float y = (volatile float)(lo1 * hi2);
-    float z = (volatile float)(hi1 * lo2);
-    float w = (volatile float)(hi1 * hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(lo3);
+    float x = lo1 * lo2;
+    float y = lo1 * hi2;
+    float z = hi1 * lo2;
+    float w = hi1 * hi2;
     if (isnan(x)) x = 0.0f; /* 0 * inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 * inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 * inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 * inf -> 0 */
-    volatile float lo = fast_fmin4_float(x, y, z, w) + lo3;
+    VOLATILE float lo = fast_fmin4_float(x, y, z, w) + lo3;
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
 
-extern float rounded_hw_interval_div_float_up(float lo1, float hi1, float lo2, float hi2)
+extern float rounded_hw_interval_div_float_up(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    float x = (volatile float)(lo1 / lo2);
-    float y = (volatile float)(lo1 / hi2);
-    float z = (volatile float)(hi1 / lo2);
-    float w = (volatile float)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    float x = lo1 / lo2;
+    float y = lo1 / hi2;
+    float z = hi1 / lo2;
+    float w = hi1 / hi2;
     if (isnan(x)) x = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
-    float hi = fast_fmax4_float(x, y, z, w);
+    VOLATILE float hi = fast_fmax4_float(x, y, z, w);
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern float rounded_hw_interval_div_float_down(float lo1, float hi1, float lo2, float hi2)
+extern float rounded_hw_interval_div_float_down(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    float x = (volatile float)(lo1 / lo2);
-    float y = (volatile float)(lo1 / hi2);
-    float z = (volatile float)(hi1 / lo2);
-    float w = (volatile float)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    float x = lo1 / lo2;
+    float y = lo1 / hi2;
+    float z = hi1 / lo2;
+    float w = hi1 / hi2;
     if (isnan(x)) x = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
-    float lo = fast_fmin4_float(x, y, z, w);
+    VOLATILE float lo = fast_fmin4_float(x, y, z, w);
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
 
-extern float rounded_hw_interval_div_add_float_up(float lo1, float hi1, float lo2, float hi2, float hi3)
+extern float rounded_hw_interval_div_add_float_up(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2, VOLATILE float hi3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_UPWARD);
-    float x = (volatile float)(lo1 / lo2);
-    float y = (volatile float)(lo1 / hi2);
-    float z = (volatile float)(hi1 / lo2);
-    float w = (volatile float)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(hi3);
+    float x = lo1 / lo2;
+    float y = lo1 / hi2;
+    float z = hi1 / lo2;
+    float w = hi1 / hi2;
     if (isnan(x)) x = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
-    volatile float hi = fast_fmax4_float(x, y, z, w) + hi3;
+    VOLATILE float hi = fast_fmax4_float(x, y, z, w) + hi3;
+    FORCE_EVAL(hi);
     restore_fp_reg(oldreg);
     return hi;
 }
 
-extern float rounded_hw_interval_div_add_float_down(float lo1, float hi1, float lo2, float hi2, float lo3)
+extern float rounded_hw_interval_div_add_float_down(VOLATILE float lo1, VOLATILE float hi1, VOLATILE float lo2, VOLATILE float hi2, VOLATILE float lo3)
 {
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, ROUND_DOWNWARD);
-    float x = (volatile float)(lo1 / lo2);
-    float y = (volatile float)(lo1 / hi2);
-    float z = (volatile float)(hi1 / lo2);
-    float w = (volatile float)(hi1 / hi2);
+    MAY_MODIFY(lo1);
+    MAY_MODIFY(hi1);
+    MAY_MODIFY(lo2);
+    MAY_MODIFY(hi2);
+    MAY_MODIFY(lo3);
+    float x = lo1 / lo2;
+    float y = lo1 / hi2;
+    float z = hi1 / lo2;
+    float w = hi1 / hi2;
     if (isnan(x)) x = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(y)) y = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(z)) z = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
     if (isnan(w)) w = 0.0f; /* 0 / 0, +-inf / +-inf -> 0 */
-    volatile float lo = fast_fmin4_float(x, y, z, w) + lo3;
+    VOLATILE float lo = fast_fmin4_float(x, y, z, w) + lo3;
+    FORCE_EVAL(lo);
     restore_fp_reg(oldreg);
     return lo;
 }
@@ -740,10 +906,12 @@
     native_rounding_mode nmode = hs_rounding_mode_to_native(mode);
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, nmode);
-    volatile float s = 0.0f;
+    VOLATILE float s = 0.0f;
+    MAY_MODIFY(s);
     for (HsInt i = 0; i < length; ++i) {
         s += a[offset + i];
     }
+    FORCE_EVAL(s);
     restore_fp_reg(oldreg);
     return s;
 }
@@ -808,8 +976,24 @@
     native_rounding_mode nmode = hs_rounding_mode_to_native(mode);
     fp_reg oldreg = get_fp_reg();
     set_rounding(oldreg, nmode);
+#if defined(__GNUC__) && defined(USE_SSE2)
+    // mingw-w64's sqrtf may use x87 instead of SSE2
+    HsInt i = 0;
+    for (; i + 4 <= length; i += 4) {
+        __m128 aa = _mm_loadu_ps(&a[offsetA + i]);
+        __m128 bb = _mm_sqrt_ps(aa);
+        _mm_storeu_ps(&result[offsetR + i], bb);
+    }
+    for (; i < length; ++i) {
+        float aa = a[offsetA + i];
+        float bb;
+        __asm__ volatile("sqrtss %1, %0" : "=x"(bb) : "x"(aa));
+        result[offsetR + i] = bb;
+    }
+#else
     for (HsInt i = 0; i < length; ++i) {
         result[offsetR + i] = sqrtf(a[offsetA + i]);
     }
+#endif
     restore_fp_reg(oldreg);
 }
diff --git a/cbits/rounded.c b/cbits/rounded.c
--- a/cbits/rounded.c
+++ b/cbits/rounded.c
@@ -43,6 +43,20 @@
 #error "Invalid configuration detected: USE_SSE2 and USE_AVX512 are mutually exclusive"
 #endif
 
+#if defined(__GNUC__) && defined(__SSE2__)
+#define MAY_MODIFY(x) __asm__ volatile("" : "+x"(x))
+#define FORCE_EVAL(x) __asm__ volatile("" : : "x"(x))
+#define VOLATILE
+#elif defined(__GNUC__) && defined(__aarch64__)
+#define MAY_MODIFY(x) __asm__ volatile("" : "+w"(x))
+#define FORCE_EVAL(x) __asm__ volatile("" : : "w"(x))
+#define VOLATILE
+#else
+#define MAY_MODIFY(x) (void)(x)
+#define FORCE_EVAL(x) (void)(x)
+#define VOLATILE volatile
+#endif
+
 #if defined(USE_AVX512)
 
 #include <x86intrin.h>
diff --git a/rounded-hw.cabal b/rounded-hw.cabal
--- a/rounded-hw.cabal
+++ b/rounded-hw.cabal
@@ -1,7 +1,8 @@
-cabal-version: 2.2
+cabal-version: 3.0
+-- asm-sources is Cabal 3.0 feature
 
 name:           rounded-hw
-version:        0.3.0
+version:        0.4.0
 synopsis:       Directed rounding for built-in floating types
 description:    Please see the README on GitHub at <https://github.com/minoki/haskell-floating-point/tree/master/rounded-hw#readme>
 category:       Numeric, Math
@@ -9,18 +10,19 @@
 bug-reports:    https://github.com/minoki/haskell-floating-point/issues
 author:         ARATA Mizuki
 maintainer:     minorinoki@gmail.com
-copyright:      2020 ARATA Mizuki
+copyright:      2020-2023 ARATA Mizuki
 license:        BSD-3-Clause
 license-file:   LICENSE
 build-type:     Custom
 tested-with:
-    GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.1
+    GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.8, GHC == 9.4.8, GHC == 9.6.3, GHC == 9.8.1
 extra-source-files:
     README.md
     ChangeLog.md
     cbits/rounded-common.inl
     cbits/rounded-avx512.inl
     cbits/interval-prim-x86_64-sse2.S
+    cbits/interval-prim-x86_64-avx512.S
 
 source-repository head
   type: git
@@ -30,8 +32,8 @@
 -- Custom setup is required to allow assembly sources to #include "ghcconfig.h"
 custom-setup
   setup-depends:
-      Cabal >=1.24
-    , base >=4.7
+      Cabal >=3.0 && <3.11
+    , base >=4.12 && <4.20
 
 flag pure-hs
   description: Disable FFI
@@ -56,7 +58,7 @@
 flag x87-long-double
   description: Support x87 "long double"
   manual: True
-  default: True
+  default: False
 
 flag float128
   description: Support Float128
@@ -65,12 +67,12 @@
 
 common deps
   build-depends:
-      array
-    , base >=4.12 && <5
-    , deepseq
+      array >=0.5.2.0 && <0.6
+    , base >=4.12 && <4.20
+    , deepseq >=1.4.4.0 && <1.6
     , fp-ieee ==0.1.*
-    , primitive
-    , vector
+    , primitive >=0.6.1.1 && <0.10
+    , vector >=0.12.0.1 && <0.14
 
 common options
   ghc-options: -Wcompat
@@ -101,7 +103,7 @@
   hs-source-dirs:
       src
   build-depends:
-      tagged
+      tagged >=0.8.6 && <0.9
   ghc-options: -Wall
   -- Use FFI when flag(pure-hs) is off
   if !flag(pure-hs)
@@ -124,12 +126,20 @@
     exposed-modules:
         Numeric.Rounded.Hardware.Backend.FastFFI
     cpp-options: -DUSE_GHC_PRIM
-    if flag(avx512)
-      c-sources:
-          cbits/interval-prim-x86_64-avx512.S
+    if impl(ghc >= 9.2)
+      if flag(avx512)
+        asm-sources:
+            cbits/interval-prim-x86_64-avx512.S
+      else
+        asm-sources:
+            cbits/interval-prim-x86_64.S
     else
-      c-sources:
-          cbits/interval-prim-x86_64.S
+      if flag(avx512)
+        c-sources:
+            cbits/interval-prim-x86_64-avx512.S
+      else
+        c-sources:
+            cbits/interval-prim-x86_64.S
   -- flag(x87-long-double): Support LongDouble on x86
   if flag(x87-long-double) && (arch(i386) || arch(x86_64))
     other-modules:
@@ -138,7 +148,7 @@
     c-sources:
         cbits/rounded-x87longdouble.c
     build-depends:
-        long-double
+        long-double >=0.1 && <0.2
   -- flag(float128): Support Float128
   if flag(float128)
     other-modules:
@@ -147,7 +157,7 @@
     c-sources:
         cbits/rounded-float128.c
     build-depends:
-        float128
+        float128 >=0.1 && <0.2
   default-language: Haskell2010
 
 test-suite rounded-hw-doctests
@@ -155,8 +165,10 @@
   type: exitcode-stdio-1.0
   main-is: doctests.hs
   build-depends:
-      doctest >=0.8
+      doctest ^>=0.22.2
   default-language: Haskell2010
+  if impl(ghc >= 9.8)
+    buildable: False
 
 test-suite rounded-hw-test
   import: deps, options
@@ -175,9 +187,9 @@
       test
   ghc-options: -threaded -rtsopts -with-rtsopts=-N
   build-depends:
-      QuickCheck
-    , hspec
-    , random
+      QuickCheck ^>=2.14.3
+    , hspec ^>=2.11.7
+    , random ^>=1.2.1.1
     , rounded-hw
   if flag(x87-long-double) && (arch(i386) || (arch(x86_64) && !os(windows)))
     -- Support for 80-bit long double is not good on Win64, so don't test
@@ -205,7 +217,5 @@
       benchmark
   build-depends:
       rounded-hw
-    , tasty-bench
-  mixins:
-      tasty-bench (Test.Tasty.Bench as Gauge, Test.Tasty.Bench as Gauge.Main, Test.Tasty.Bench as Gauge.Benchmark)
+    , tasty-bench ^>=0.3.5
   default-language: Haskell2010
diff --git a/src/Numeric/Rounded/Hardware/Backend/C.hs b/src/Numeric/Rounded/Hardware/Backend/C.hs
--- a/src/Numeric/Rounded/Hardware/Backend/C.hs
+++ b/src/Numeric/Rounded/Hardware/Backend/C.hs
@@ -90,11 +90,6 @@
   (F.roundedFromWord64 r x)
 {-# INLINE roundedFloatFromWord64 #-}
 
-intervalFloatFromInteger :: Integer -> (Rounded 'TowardNegInf Float, Rounded 'TowardInf Float)
-intervalFloatFromInteger x
-  | -0x1000000 <= x && x <= 0x1000000 {- abs x <= 2^24 -} = (Rounded (fromInteger x), Rounded (fromInteger x))
-  | otherwise = intervalFromInteger_default x
-
 roundedFloatFromRealFloat :: RealFloat a => RoundingMode -> a -> Float
 roundedFloatFromRealFloat r x | isNaN x = 0/0
                               | isInfinite x = if x > 0 then 1/0 else -1/0
diff --git a/src/Numeric/Rounded/Hardware/Backend/Default.hs b/src/Numeric/Rounded/Hardware/Backend/Default.hs
--- a/src/Numeric/Rounded/Hardware/Backend/Default.hs
+++ b/src/Numeric/Rounded/Hardware/Backend/Default.hs
@@ -89,6 +89,7 @@
   map_roundedSqrt mode vec = unsafeCoerce (map_roundedSqrt mode (unsafeCoerce vec) :: VS.Vector DoubleImpl)
   {-# INLINE map_roundedSqrt #-}
 
+#if !MIN_VERSION_base(4, 16, 0)
 -- orphaned rules
 {-# RULES
 "fromIntegral/a->Rounded ToNearest Float"
@@ -108,3 +109,4 @@
 "fromIntegral/a->Rounded TowardZero Double"
   fromIntegral = \x -> (Rounded (fromIntegralTowardZero x) :: Rounded 'TowardZero Double)
   #-}
+#endif
diff --git a/src/Numeric/Rounded/Hardware/Backend/FastFFI.hs b/src/Numeric/Rounded/Hardware/Backend/FastFFI.hs
--- a/src/Numeric/Rounded/Hardware/Backend/FastFFI.hs
+++ b/src/Numeric/Rounded/Hardware/Backend/FastFFI.hs
@@ -50,8 +50,8 @@
 import           Foreign.Storable (Storable)
 import           GHC.Exts
 import           GHC.Generics (Generic)
-import           GHC.Int (Int64 (I64#))
-import           GHC.Word (Word64 (W64#))
+-- import           GHC.Int (Int64 (I64#))
+-- import           GHC.Word (Word64 (W64#))
 import qualified Numeric.Rounded.Hardware.Backend.C as C
 import           Numeric.Rounded.Hardware.Internal.Class
 import           System.IO.Unsafe (unsafePerformIO)
@@ -166,6 +166,7 @@
                          , Double#  -- upper, %xmm2
                          #)
 
+{-
 foreign import prim "rounded_hw_interval_sqrt"
   fastIntervalSqrt# :: Double# -- lower 1, %xmm1
                     -> Double# -- upper 1, %xmm2
@@ -173,7 +174,7 @@
                         , Double#  -- upper, %xmm2
                         #)
 
-#if WORD_SIZE_IN_BITS >= 64
+#if WORD_SIZE_IN_BITS >= 64 && !MIN_VERSION_base(4,17,0)
 type INT64# = Int#
 type WORD64# = Word#
 #else
@@ -187,7 +188,6 @@
                              , Double# -- upper, %xmm2
                              #)
 
-{-
 foreign import prim "rounded_hw_interval_from_word64"
   fastIntervalFromWord64# :: WORD64# -- value
                           -> (# Double# -- lower, %xmm1
@@ -210,6 +210,7 @@
   (# l2, h2 #) -> (D# l2, D# h2)
 {-# INLINE fastIntervalRecip #-}
 
+{-
 fastIntervalSqrt :: Double -> Double -> (Double, Double)
 fastIntervalSqrt (D# l1) (D# h1) = case fastIntervalSqrt# l1 h1 of
   (# l2, h2 #) -> (D# l2, D# h2)
@@ -220,7 +221,6 @@
   (# l, h #) -> (D# l, D# h)
 {-# INLINE fastIntervalFromInt64 #-}
 
-{-
 fastIntervalFromWord64 :: Word64 -> (Double, Double)
 fastIntervalFromWord64 (W64# x) = case fastIntervalFromWord64# x of
   (# l, h #) -> (D# l, D# h)
diff --git a/src/Numeric/Rounded/Hardware/Backend/ViaRational.hs b/src/Numeric/Rounded/Hardware/Backend/ViaRational.hs
--- a/src/Numeric/Rounded/Hardware/Backend/ViaRational.hs
+++ b/src/Numeric/Rounded/Hardware/Backend/ViaRational.hs
@@ -54,7 +54,7 @@
             TowardInf    ->  0
             TowardZero   ->  0
   roundedMul r (ViaRational x) (ViaRational y)
-    | isNaN x || isNaN y || isInfinite x || isInfinite y || isNegativeZero x || isNegativeZero y = ViaRational (x * y)
+    | isNaN x || isNaN y || isInfinite x || isInfinite y || x == 0 || y == 0 = ViaRational (x * y)
     | otherwise = roundedFromRational r (toRational x * toRational y)
   roundedFusedMultiplyAdd r (ViaRational x) (ViaRational y) (ViaRational z)
     | isFinite x && isFinite y && isFinite z = case toRational x * toRational y + toRational z of
diff --git a/src/Numeric/Rounded/Hardware/Interval.hs b/src/Numeric/Rounded/Hardware/Interval.hs
--- a/src/Numeric/Rounded/Hardware/Interval.hs
+++ b/src/Numeric/Rounded/Hardware/Interval.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
@@ -316,9 +317,11 @@
     in pairToInterval (x, y)
   -- unsafeReplace, unsafeAccum, unsafeAccumArray: Use default
 
+#if !MIN_VERSION_base(4, 16, 0)
 {-# RULES
 "fromIntegral/a->Interval Float"
   fromIntegral = \x -> case intervalFromIntegral x of (l, u) -> I l u :: Interval Float
 "fromIntegral/a->Interval Double"
   fromIntegral = \x -> case intervalFromIntegral x of (l, u) -> I l u :: Interval Double
   #-}
+#endif
diff --git a/src/Numeric/Rounded/Hardware/Interval/NonEmpty.hs b/src/Numeric/Rounded/Hardware/Interval/NonEmpty.hs
--- a/src/Numeric/Rounded/Hardware/Interval/NonEmpty.hs
+++ b/src/Numeric/Rounded/Hardware/Interval/NonEmpty.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
@@ -355,9 +356,11 @@
     in pairToInterval (x, y)
   -- unsafeReplace, unsafeAccum, unsafeAccumArray: Use default
 
+#if !MIN_VERSION_base(4, 16, 0)
 {-# RULES
 "fromIntegral/a->Interval Float"
   fromIntegral = \x -> case intervalFromIntegral x of (l, u) -> I l u :: Interval Float
 "fromIntegral/a->Interval Double"
   fromIntegral = \x -> case intervalFromIntegral x of (l, u) -> I l u :: Interval Double
   #-}
+#endif
