[libc-commits] [libc] 9fb049c - [libc][math][c23] Add {f, d}mul{l, f128} and f16mul{, f, l, f128} C23 math functions (#98972)

via libc-commits libc-commits at lists.llvm.org
Thu Jul 18 10:50:52 PDT 2024


Author: OverMighty
Date: 2024-07-18T19:50:49+02:00
New Revision: 9fb049c8c6a77026fa75a8d36b386a7f5a60613a

URL: https://github.com/llvm/llvm-project/commit/9fb049c8c6a77026fa75a8d36b386a7f5a60613a
DIFF: https://github.com/llvm/llvm-project/commit/9fb049c8c6a77026fa75a8d36b386a7f5a60613a.diff

LOG: [libc][math][c23] Add {f,d}mul{l,f128} and f16mul{,f,l,f128} C23 math functions (#98972)

Part of #93566.
                
Fixes #94833.

Added: 
    libc/src/__support/FPUtil/generic/mul.h
    libc/src/math/dmulf128.h
    libc/src/math/dmull.h
    libc/src/math/f16mul.h
    libc/src/math/f16mulf.h
    libc/src/math/f16mulf128.h
    libc/src/math/f16mull.h
    libc/src/math/fmulf128.h
    libc/src/math/fmull.h
    libc/src/math/generic/dmulf128.cpp
    libc/src/math/generic/dmull.cpp
    libc/src/math/generic/f16mul.cpp
    libc/src/math/generic/f16mulf.cpp
    libc/src/math/generic/f16mulf128.cpp
    libc/src/math/generic/f16mull.cpp
    libc/src/math/generic/fmulf128.cpp
    libc/src/math/generic/fmull.cpp
    libc/test/src/math/MulTest.h
    libc/test/src/math/dmull_test.cpp
    libc/test/src/math/f16mul_test.cpp
    libc/test/src/math/f16mulf_test.cpp
    libc/test/src/math/f16mull_test.cpp
    libc/test/src/math/fmull_test.cpp
    libc/test/src/math/smoke/MulTest.h
    libc/test/src/math/smoke/dmulf128_test.cpp
    libc/test/src/math/smoke/dmull_test.cpp
    libc/test/src/math/smoke/f16mul_test.cpp
    libc/test/src/math/smoke/f16mulf128_test.cpp
    libc/test/src/math/smoke/f16mulf_test.cpp
    libc/test/src/math/smoke/f16mull_test.cpp
    libc/test/src/math/smoke/fmulf128_test.cpp
    libc/test/src/math/smoke/fmull_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/docs/math/index.rst
    libc/spec/llvm_libc_ext.td
    libc/spec/stdc.td
    libc/src/__support/FPUtil/generic/CMakeLists.txt
    libc/src/math/CMakeLists.txt
    libc/src/math/generic/CMakeLists.txt
    libc/src/math/generic/fmul.cpp
    libc/test/src/math/CMakeLists.txt
    libc/test/src/math/fmul_test.cpp
    libc/test/src/math/smoke/CMakeLists.txt
    libc/test/src/math/smoke/fmul_test.cpp
    libc/utils/MPFRWrapper/MPFRUtils.cpp
    libc/utils/MPFRWrapper/MPFRUtils.h

Removed: 
    libc/test/src/math/FMulTest.h
    libc/test/src/math/smoke/FMulTest.h


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 9b718c3f81151..208889ba34a59 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -357,6 +357,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.cosf
     libc.src.math.coshf
     libc.src.math.cospif
+    libc.src.math.dmull
     libc.src.math.erff
     libc.src.math.exp
     libc.src.math.exp10
@@ -411,6 +412,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.fmodf
     libc.src.math.fmodl
     libc.src.math.fmul
+    libc.src.math.fmull
     libc.src.math.frexp
     libc.src.math.frexpf
     libc.src.math.frexpl
@@ -531,6 +533,8 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.f16div
     libc.src.math.f16divf
     libc.src.math.f16fmaf
+    libc.src.math.f16mul
+    libc.src.math.f16mulf
     libc.src.math.f16sqrt
     libc.src.math.f16sqrtf
     libc.src.math.f16sub

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 4d19a28f4a2b3..cbdee084aa199 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -382,6 +382,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.cosf
     libc.src.math.coshf
     libc.src.math.cospif
+    libc.src.math.dmull
     libc.src.math.erff
     libc.src.math.exp
     libc.src.math.exp10
@@ -437,6 +438,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.fmodf
     libc.src.math.fmodl
     libc.src.math.fmul
+    libc.src.math.fmull
     libc.src.math.frexp
     libc.src.math.frexpf
     libc.src.math.frexpl
@@ -561,6 +563,9 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.f16fma
     libc.src.math.f16fmaf
     libc.src.math.f16fmal
+    libc.src.math.f16mul
+    libc.src.math.f16mulf
+    libc.src.math.f16mull
     libc.src.math.f16sqrt
     libc.src.math.f16sqrtf
     libc.src.math.f16sqrtl
@@ -622,6 +627,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
       libc.src.math.f16addf128
       libc.src.math.f16divf128
       libc.src.math.f16fmaf128
+      libc.src.math.f16mulf128
       libc.src.math.f16sqrtf128
       libc.src.math.f16subf128
     )
@@ -634,6 +640,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
     libc.src.math.canonicalizef128
     libc.src.math.ceilf128
     libc.src.math.copysignf128
+    libc.src.math.dmulf128
     libc.src.math.fabsf128
     libc.src.math.fdimf128
     libc.src.math.floorf128
@@ -648,6 +655,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
     libc.src.math.fminimum_numf128
     libc.src.math.fminimumf128
     libc.src.math.fmodf128
+    libc.src.math.fmulf128
     libc.src.math.frexpf128
     libc.src.math.fromfpf128
     libc.src.math.fromfpxf128

diff  --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index 205d14946535e..5fab9ce4df949 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -120,7 +120,7 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | dfma             | N/A              | N/A             |                        | N/A                  |                        | 7.12.14.5              | F.10.11                    |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| dmul             | N/A              | N/A             |                        | N/A                  |                        | 7.12.14.3              | F.10.11                    |
+| dmul             | N/A              | N/A             | |check|                | N/A                  | |check|\*              | 7.12.14.3              | F.10.11                    |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | dsub             | N/A              | N/A             |                        | N/A                  |                        | 7.12.14.2              | F.10.11                    |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
@@ -130,6 +130,8 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | f16fma           | |check|\*        | |check|\*       | |check|\*              | N/A                  | |check|                | 7.12.14.5              | F.10.11                    |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
+| f16mul           | |check|\*        | |check|\*       | |check|\*              | N/A                  | |check|                | 7.12.14.5              | F.10.11                    |
++------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | f16sub           | |check|\*        | |check|\*       | |check|\*              | N/A                  | |check|                | 7.12.14.2              | F.10.11                    |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | fabs             | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.7.3               | F.10.4.3                   |
@@ -166,7 +168,7 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | fmod             | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.10.1              | F.10.7.1                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| fmul             | N/A              | |check|         |                        | N/A                  |                        | 7.12.14.3              | F.10.11                    |
+| fmul             | N/A              | |check|         | |check|                | N/A                  | |check|\*              | 7.12.14.3              | F.10.11                    |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | frexp            | |check|          | |check|         | |check|                | |check|              | |check|                | 7.12.6.7               | F.10.3.7                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

diff  --git a/libc/spec/llvm_libc_ext.td b/libc/spec/llvm_libc_ext.td
index 86215029831ca..55b354cae74e0 100644
--- a/libc/spec/llvm_libc_ext.td
+++ b/libc/spec/llvm_libc_ext.td
@@ -65,6 +65,14 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> {
           GuardedFunctionSpec<"f16subf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
           GuardedFunctionSpec<"f16subl", RetValSpec<Float16Type>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>], "LIBC_TYPES_HAS_FLOAT16">,
 
+          GuardedFunctionSpec<"fmulf128", RetValSpec<FloatType>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
+
+          GuardedFunctionSpec<"dmulf128", RetValSpec<DoubleType>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
+
+          GuardedFunctionSpec<"f16mul", RetValSpec<Float16Type>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>], "LIBC_TYPES_HAS_FLOAT16">,
+          GuardedFunctionSpec<"f16mulf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
+          GuardedFunctionSpec<"f16mull", RetValSpec<Float16Type>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>], "LIBC_TYPES_HAS_FLOAT16">,
+
           GuardedFunctionSpec<"f16div", RetValSpec<Float16Type>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>], "LIBC_TYPES_HAS_FLOAT16">,
           GuardedFunctionSpec<"f16divf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
           GuardedFunctionSpec<"f16divl", RetValSpec<Float16Type>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>], "LIBC_TYPES_HAS_FLOAT16">,

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index a4c6b40b98388..18592e92d330a 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -475,8 +475,6 @@ def StdC : StandardSpec<"stdc"> {
           GuardedFunctionSpec<"fminimum_mag_numf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>, ArgSpec<Float16Type>], "LIBC_TYPES_HAS_FLOAT16">,
           GuardedFunctionSpec<"fminimum_mag_numf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
 
-          FunctionSpec<"fmul", RetValSpec<FloatType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
-
           FunctionSpec<"fma", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
           FunctionSpec<"fmaf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>, ArgSpec<FloatType>]>,
 
@@ -733,6 +731,13 @@ def StdC : StandardSpec<"stdc"> {
 
           GuardedFunctionSpec<"f16subf128", RetValSpec<Float16Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">,
 
+          FunctionSpec<"fmul", RetValSpec<FloatType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
+          FunctionSpec<"fmull", RetValSpec<FloatType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
+
+          FunctionSpec<"dmull", RetValSpec<DoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
+
+          GuardedFunctionSpec<"f16mulf128", RetValSpec<Float16Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">,
+
           GuardedFunctionSpec<"f16divf128", RetValSpec<Float16Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">,
 
           GuardedFunctionSpec<"f16sqrtf128", RetValSpec<Float16Type>, [ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">,

diff  --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt
index c73f68723e232..43096aa529fc3 100644
--- a/libc/src/__support/FPUtil/generic/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt
@@ -84,3 +84,20 @@ add_header_library(
     libc.src.__support.macros.attributes
     libc.src.__support.macros.optimization
 )
+
+add_header_library(
+  mul
+  HDRS
+    mul.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.CPP.bit
+    libc.src.__support.CPP.type_traits
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.dyadic_float
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.optimization
+)

diff  --git a/libc/src/__support/FPUtil/generic/mul.h b/libc/src/__support/FPUtil/generic/mul.h
new file mode 100644
index 0000000000000..02fc69c6cb1ba
--- /dev/null
+++ b/libc/src/__support/FPUtil/generic/mul.h
@@ -0,0 +1,105 @@
+//===-- Multiplication of IEEE 754 floating-point numbers -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_MUL_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_MUL_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/FPUtil/BasicOperations.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/dyadic_float.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil::generic {
+
+template <typename OutType, typename InType>
+LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<OutType> &&
+                                 cpp::is_floating_point_v<InType> &&
+                                 sizeof(OutType) <= sizeof(InType),
+                             OutType>
+mul(InType x, InType y) {
+  using OutFPBits = FPBits<OutType>;
+  using OutStorageType = typename OutFPBits::StorageType;
+  using InFPBits = FPBits<InType>;
+  using InStorageType = typename InFPBits::StorageType;
+  // The product of two p-digit numbers is a 2p-digit number.
+  using DyadicFloat =
+      DyadicFloat<cpp::bit_ceil(2 * static_cast<size_t>(InFPBits::SIG_LEN))>;
+
+  InFPBits x_bits(x);
+  InFPBits y_bits(y);
+
+  Sign result_sign = x_bits.sign() == y_bits.sign() ? Sign::POS : Sign::NEG;
+
+  if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() ||
+                    x_bits.is_zero() || y_bits.is_zero())) {
+    if (x_bits.is_nan() || y_bits.is_nan()) {
+      if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+        raise_except_if_required(FE_INVALID);
+
+      if (x_bits.is_quiet_nan()) {
+        InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
+        if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
+          return OutFPBits::quiet_nan(x_bits.sign(),
+                                      static_cast<OutStorageType>(x_payload))
+              .get_val();
+      }
+
+      if (y_bits.is_quiet_nan()) {
+        InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
+        if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
+          return OutFPBits::quiet_nan(y_bits.sign(),
+                                      static_cast<OutStorageType>(y_payload))
+              .get_val();
+      }
+
+      return OutFPBits::quiet_nan().get_val();
+    }
+
+    if (x_bits.is_inf()) {
+      if (y_bits.is_zero()) {
+        set_errno_if_required(EDOM);
+        raise_except_if_required(FE_INVALID);
+        return OutFPBits::quiet_nan().get_val();
+      }
+
+      return OutFPBits::inf(result_sign).get_val();
+    }
+
+    if (y_bits.is_inf()) {
+      if (x_bits.is_zero()) {
+        set_errno_if_required(EDOM);
+        raise_except_if_required(FE_INVALID);
+        return OutFPBits::quiet_nan().get_val();
+      }
+
+      return OutFPBits::inf(result_sign).get_val();
+    }
+
+    // Now either x or y is zero, and the other one is finite.
+    return OutFPBits::zero(result_sign).get_val();
+  }
+
+  DyadicFloat xd(x);
+  DyadicFloat yd(y);
+
+  DyadicFloat result = quick_mul(xd, yd);
+  return result.template as<OutType, /*ShouldSignalExceptions=*/true>();
+}
+
+} // namespace fputil::generic
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_MUL_H

diff  --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index dc2339896f2bb..c4e33130e9090 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -86,6 +86,9 @@ add_math_entrypoint_object(cosh)
 add_math_entrypoint_object(coshf)
 add_math_entrypoint_object(cospif)
 
+add_math_entrypoint_object(dmull)
+add_math_entrypoint_object(dmulf128)
+
 add_math_entrypoint_object(erf)
 add_math_entrypoint_object(erff)
 
@@ -118,6 +121,11 @@ add_math_entrypoint_object(f16fmaf)
 add_math_entrypoint_object(f16fmal)
 add_math_entrypoint_object(f16fmaf128)
 
+add_math_entrypoint_object(f16mul)
+add_math_entrypoint_object(f16mulf)
+add_math_entrypoint_object(f16mull)
+add_math_entrypoint_object(f16mulf128)
+
 add_math_entrypoint_object(f16sqrt)
 add_math_entrypoint_object(f16sqrtf)
 add_math_entrypoint_object(f16sqrtl)
@@ -210,6 +218,8 @@ add_math_entrypoint_object(fminimum_mag_numf16)
 add_math_entrypoint_object(fminimum_mag_numf128)
 
 add_math_entrypoint_object(fmul)
+add_math_entrypoint_object(fmull)
+add_math_entrypoint_object(fmulf128)
 
 add_math_entrypoint_object(fmod)
 add_math_entrypoint_object(fmodf)

diff  --git a/libc/src/math/dmulf128.h b/libc/src/math/dmulf128.h
new file mode 100644
index 0000000000000..623f22c910a41
--- /dev/null
+++ b/libc/src/math/dmulf128.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for dmulf128 ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_DMULF128_H
+#define LLVM_LIBC_SRC_MATH_DMULF128_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+double dmulf128(float128 x, float128 y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_DMULF128_H

diff  --git a/libc/src/math/dmull.h b/libc/src/math/dmull.h
new file mode 100644
index 0000000000000..656776a603009
--- /dev/null
+++ b/libc/src/math/dmull.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for dmull -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_DMULL_H
+#define LLVM_LIBC_SRC_MATH_DMULL_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+double dmull(long double x, long double y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_DMULL_H

diff  --git a/libc/src/math/f16mul.h b/libc/src/math/f16mul.h
new file mode 100644
index 0000000000000..89403cf219271
--- /dev/null
+++ b/libc/src/math/f16mul.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for f16mul ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_F16MUL_H
+#define LLVM_LIBC_SRC_MATH_F16MUL_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 f16mul(double x, double y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_F16MUL_H

diff  --git a/libc/src/math/f16mulf.h b/libc/src/math/f16mulf.h
new file mode 100644
index 0000000000000..755886d6f14d0
--- /dev/null
+++ b/libc/src/math/f16mulf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for f16mulf -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_F16MULF_H
+#define LLVM_LIBC_SRC_MATH_F16MULF_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 f16mulf(float x, float y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_F16MULF_H

diff  --git a/libc/src/math/f16mulf128.h b/libc/src/math/f16mulf128.h
new file mode 100644
index 0000000000000..14371c57ca88c
--- /dev/null
+++ b/libc/src/math/f16mulf128.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for f16mulf128 --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_F16MULF128_H
+#define LLVM_LIBC_SRC_MATH_F16MULF128_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 f16mulf128(float128 x, float128 y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_F16MULF128_H

diff  --git a/libc/src/math/f16mull.h b/libc/src/math/f16mull.h
new file mode 100644
index 0000000000000..a3177cadc1306
--- /dev/null
+++ b/libc/src/math/f16mull.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for f16mull -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_F16MULL_H
+#define LLVM_LIBC_SRC_MATH_F16MULL_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 f16mull(long double x, long double y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_F16MULL_H

diff  --git a/libc/src/math/fmulf128.h b/libc/src/math/fmulf128.h
new file mode 100644
index 0000000000000..94137ae87eb1e
--- /dev/null
+++ b/libc/src/math/fmulf128.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for fmulf128 ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FMULF128_H
+#define LLVM_LIBC_SRC_MATH_FMULF128_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float fmulf128(float128 x, float128 y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_FMULF128_H

diff  --git a/libc/src/math/fmull.h b/libc/src/math/fmull.h
new file mode 100644
index 0000000000000..46e6c77cc66a2
--- /dev/null
+++ b/libc/src/math/fmull.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for fmull -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FMULL_H
+#define LLVM_LIBC_SRC_MATH_FMULL_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float fmull(long double x, long double y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_FMULL_H

diff  --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 415ca3fbce796..9c86bac4a0cb7 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -2633,11 +2633,32 @@ add_entrypoint_object(
   HDRS
     ../fmul.h
   DEPENDS
-    libc.src.__support.FPUtil.basic_operations
-    libc.src.__support.uint128
-    libc.src.__support.CPP.bit
-    libc.src.__support.FPUtil.fp_bits
-    libc.src.__support.FPUtil.rounding_mode
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  fmull
+  SRCS
+    fmull.cpp
+  HDRS
+    ../fmull.h
+  DEPENDS
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  fmulf128
+  SRCS
+    fmulf128.cpp
+  HDRS
+    ../fmulf128.h
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.generic.mul
   COMPILE_OPTIONS
     -O3
 )
@@ -4200,3 +4221,80 @@ add_entrypoint_object(
     libc.src.__support.macros.optimization
     libc.src.__support.integer_literals
 )
+
+add_entrypoint_object(
+  dmull
+  SRCS
+    dmull.cpp
+  HDRS
+    ../dmull.h
+  DEPENDS
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  dmulf128
+  SRCS
+    dmulf128.cpp
+  HDRS
+    ../dmulf128.h
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  f16mul
+  SRCS
+    f16mul.cpp
+  HDRS
+    ../f16mul.h
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  f16mulf
+  SRCS
+    f16mulf.cpp
+  HDRS
+    ../f16mulf.h
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  f16mull
+  SRCS
+    f16mull.cpp
+  HDRS
+    ../f16mull.h
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)
+
+add_entrypoint_object(
+  f16mulf128
+  SRCS
+    f16mulf128.cpp
+  HDRS
+    ../f16mulf128.h
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.generic.mul
+  COMPILE_OPTIONS
+    -O3
+)

diff  --git a/libc/src/math/generic/dmulf128.cpp b/libc/src/math/generic/dmulf128.cpp
new file mode 100644
index 0000000000000..7e6ef95362c09
--- /dev/null
+++ b/libc/src/math/generic/dmulf128.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of dmulf128 function -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/dmulf128.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(double, dmulf128, (float128 x, float128 y)) {
+  return fputil::generic::mul<double>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/dmull.cpp b/libc/src/math/generic/dmull.cpp
new file mode 100644
index 0000000000000..428caa84a9977
--- /dev/null
+++ b/libc/src/math/generic/dmull.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of dmull function ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/dmull.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(double, dmull, (long double x, long double y)) {
+  return fputil::generic::mul<double>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/f16mul.cpp b/libc/src/math/generic/f16mul.cpp
new file mode 100644
index 0000000000000..f7a5225b60f11
--- /dev/null
+++ b/libc/src/math/generic/f16mul.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of f16mul function ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/f16mul.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, f16mul, (double x, double y)) {
+  return fputil::generic::mul<float16>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/f16mulf.cpp b/libc/src/math/generic/f16mulf.cpp
new file mode 100644
index 0000000000000..2c04664f804ea
--- /dev/null
+++ b/libc/src/math/generic/f16mulf.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of f16mulf function --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/f16mulf.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, f16mulf, (float x, float y)) {
+  return fputil::generic::mul<float16>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/f16mulf128.cpp b/libc/src/math/generic/f16mulf128.cpp
new file mode 100644
index 0000000000000..7e2d6a0d194ae
--- /dev/null
+++ b/libc/src/math/generic/f16mulf128.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of f16mulf128 function -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/f16mulf128.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, f16mulf128, (float128 x, float128 y)) {
+  return fputil::generic::mul<float16>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/f16mull.cpp b/libc/src/math/generic/f16mull.cpp
new file mode 100644
index 0000000000000..fc66fba4d9f23
--- /dev/null
+++ b/libc/src/math/generic/f16mull.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of f16mull function --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/f16mull.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, f16mull, (long double x, long double y)) {
+  return fputil::generic::mul<float16>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/fmul.cpp b/libc/src/math/generic/fmul.cpp
index 16fa11e93df09..64c27d6e2f956 100644
--- a/libc/src/math/generic/fmul.cpp
+++ b/libc/src/math/generic/fmul.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of fmul function------------------------------------===//
+//===-- Implementation of fmul function -----------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,123 +7,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/math/fmul.h"
-#include "src/__support/CPP/bit.h"
-#include "src/__support/FPUtil/BasicOperations.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/FPUtil/generic/mul.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/uint128.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float, fmul, (double x, double y)) {
-  auto x_bits = fputil::FPBits<double>(x);
-
-  auto y_bits = fputil::FPBits<double>(y);
-
-  auto output_sign = (x_bits.sign() != y_bits.sign()) ? Sign::NEG : Sign::POS;
-
-  if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() ||
-                    x_bits.is_zero() || y_bits.is_zero())) {
-    if (x_bits.is_nan())
-      return static_cast<float>(x);
-    if (y_bits.is_nan())
-      return static_cast<float>(y);
-    if (x_bits.is_inf())
-      return y_bits.is_zero()
-                 ? fputil::FPBits<float>::quiet_nan().get_val()
-                 : fputil::FPBits<float>::inf(output_sign).get_val();
-    if (y_bits.is_inf())
-      return x_bits.is_zero()
-                 ? fputil::FPBits<float>::quiet_nan().get_val()
-                 : fputil::FPBits<float>::inf(output_sign).get_val();
-    // Now either x or y is zero, and the other one is finite.
-    return fputil::FPBits<float>::zero(output_sign).get_val();
-  }
-
-  uint64_t mx, my;
-
-  // Get mantissa and append the hidden bit if needed.
-  mx = x_bits.get_explicit_mantissa();
-  my = y_bits.get_explicit_mantissa();
-
-  // Get the corresponding biased exponent.
-  int ex = x_bits.get_explicit_exponent();
-  int ey = y_bits.get_explicit_exponent();
-
-  // Count the number of leading zeros of the explicit mantissas.
-  int nx = cpp::countl_zero(mx);
-  int ny = cpp::countl_zero(my);
-  // Shift the leading 1 bit to the most significant bit.
-  mx <<= nx;
-  my <<= ny;
-
-  // Adjust exponent accordingly: If x or y are normal, we will only need to
-  // shift by (exponent length + sign bit = 11 bits. If x or y are denormal, we
-  // will need to shift more than 11 bits.
-  ex -= (nx - 11);
-  ey -= (ny - 11);
-
-  UInt128 product = static_cast<UInt128>(mx) * static_cast<UInt128>(my);
-  int32_t dm1;
-  uint64_t highs, lows;
-  uint64_t g, hight, lowt;
-  uint32_t m;
-  uint32_t b;
-  int c;
-
-  highs = static_cast<uint64_t>(product >> 64);
-  c = static_cast<int>(highs >= 0x8000000000000000);
-  lows = static_cast<uint64_t>(product);
-
-  lowt = (lows != 0);
-
-  dm1 = ex + ey + c + fputil::FPBits<float>::EXP_BIAS;
-
-  int round_mode = fputil::quick_get_round();
-  if (dm1 >= 255) {
-    if ((round_mode == FE_TOWARDZERO) ||
-        (round_mode == FE_UPWARD && output_sign.is_neg()) ||
-        (round_mode == FE_DOWNWARD && output_sign.is_pos())) {
-      return fputil::FPBits<float>::max_normal(output_sign).get_val();
-    }
-    return fputil::FPBits<float>::inf().get_val();
-  } else if (dm1 <= 0) {
-
-    int m_shift = 40 + c - dm1;
-    int g_shift = m_shift - 1;
-    int h_shift = 64 - g_shift;
-    m = (m_shift >= 64) ? 0 : static_cast<uint32_t>(highs >> m_shift);
-
-    g = g_shift >= 64 ? 0 : (highs >> g_shift) & 1;
-    hight = h_shift >= 64 ? highs : (highs << h_shift) != 0;
-
-    dm1 = 0;
-  } else {
-    m = static_cast<uint32_t>(highs >> (39 + c));
-    g = (highs >> (38 + c)) & 1;
-    hight = (highs << (26 - c)) != 0;
-  }
-
-  if (round_mode == FE_TONEAREST) {
-    b = g && ((hight && lowt) || ((m & 1) != 0));
-  } else if ((output_sign.is_neg() && round_mode == FE_DOWNWARD) ||
-             (output_sign.is_pos() && round_mode == FE_UPWARD)) {
-    b = (g == 0 && (hight && lowt) == 0) ? 0 : 1;
-  } else {
-    b = 0;
-  }
-
-  uint32_t exp16 = (dm1 << 23);
-
-  uint32_t m2 = m & fputil::FPBits<float>::FRACTION_MASK;
-
-  uint32_t result = (exp16 + m2) + b;
-
-  auto result_bits = fputil::FPBits<float>(result);
-  result_bits.set_sign(output_sign);
-  return result_bits.get_val();
+  return fputil::generic::mul<float>(x, y);
 }
 
 } // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/fmulf128.cpp b/libc/src/math/generic/fmulf128.cpp
new file mode 100644
index 0000000000000..c0c55ace641b8
--- /dev/null
+++ b/libc/src/math/generic/fmulf128.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of fmulf128 function -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/fmulf128.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float, fmulf128, (float128 x, float128 y)) {
+  return fputil::generic::mul<float>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/math/generic/fmull.cpp b/libc/src/math/generic/fmull.cpp
new file mode 100644
index 0000000000000..41ab165e7d09d
--- /dev/null
+++ b/libc/src/math/generic/fmull.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of fmull function ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/fmull.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float, fmull, (long double x, long double y)) {
+  return fputil::generic::mul<float>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 64b4d2c58fb6a..c28385f620cfd 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1847,10 +1847,28 @@ add_fp_unittest(
   SRCS
     fmul_test.cpp
   HDRS
-    FMulTest.h
+    MulTest.h
   DEPENDS
     libc.src.math.fmul
+    libc.src.stdlib.rand
+    libc.src.stdlib.srand
 )
+
+add_fp_unittest(
+  fmull_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    fmull_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.src.math.fmull
+    libc.src.stdlib.rand
+    libc.src.stdlib.srand
+)
+
 add_fp_unittest(
   asinhf_test
   NEED_MPFR
@@ -2237,6 +2255,66 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  dmull_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    dmull_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.src.math.dmull
+    libc.src.stdlib.rand
+    libc.src.stdlib.srand
+)
+
+add_fp_unittest(
+  f16mul_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    f16mul_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.src.math.f16mul
+    libc.src.stdlib.rand
+    libc.src.stdlib.srand
+)
+
+add_fp_unittest(
+  f16mulf_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    f16mulf_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.src.math.f16mulf
+    libc.src.stdlib.rand
+    libc.src.stdlib.srand
+)
+
+add_fp_unittest(
+  f16mull_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    f16mull_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.src.math.f16mull
+    libc.src.stdlib.rand
+    libc.src.stdlib.srand
+)
+
 add_subdirectory(generic)
 add_subdirectory(smoke)
 

diff  --git a/libc/test/src/math/FMulTest.h b/libc/test/src/math/FMulTest.h
deleted file mode 100644
index 8ca33ea71b712..0000000000000
--- a/libc/test/src/math/FMulTest.h
+++ /dev/null
@@ -1,121 +0,0 @@
-//===-- Utility class to test fmul[f|l] -------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H
-#define LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H
-
-#include "src/__support/FPUtil/FPBits.h"
-#include "test/UnitTest/FEnvSafeTest.h"
-#include "test/UnitTest/FPMatcher.h"
-#include "test/UnitTest/Test.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-
-namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
-
-template <typename OutType, typename InType>
-class FmulMPFRTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
-
-  DECLARE_SPECIAL_CONSTANTS(InType)
-
-public:
-  typedef OutType (*FMulFunc)(InType, InType);
-
-  void testFMulMPFR(FMulFunc func) {
-    constexpr int N = 10;
-    mpfr::BinaryInput<InType> INPUTS[N] = {
-        {3.0, 5.0},
-        {0x1.0p1, 0x1.0p-131},
-        {0x1.0p2, 0x1.0p-129},
-        {1.0, 1.0},
-        {-0.0, -0.0},
-        {-0.0, 0.0},
-        {0.0, -0.0},
-        {0x1.0p100, 0x1.0p100},
-        {1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150},
-        {1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150}};
-
-    for (int i = 0; i < N; ++i) {
-      InType x = INPUTS[i].x;
-      InType y = INPUTS[i].y;
-      ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i],
-                                     func(x, y), 0.5);
-    }
-  }
-
-  void testSpecialInputsMPFR(FMulFunc func) {
-    constexpr int N = 27;
-    mpfr::BinaryInput<InType> INPUTS[N] = {{inf, 0x1.0p-129},
-                                           {0x1.0p-129, inf},
-                                           {inf, 2.0},
-                                           {3.0, inf},
-                                           {0.0, 0.0},
-                                           {neg_inf, aNaN},
-                                           {aNaN, neg_inf},
-                                           {neg_inf, neg_inf},
-                                           {0.0, neg_inf},
-                                           {neg_inf, 0.0},
-                                           {neg_inf, 1.0},
-                                           {1.0, neg_inf},
-                                           {neg_inf, 0x1.0p-129},
-                                           {0x1.0p-129, neg_inf},
-                                           {0.0, 0x1.0p-129},
-                                           {inf, 0.0},
-                                           {0.0, inf},
-                                           {0.0, aNaN},
-                                           {2.0, aNaN},
-                                           {0x1.0p-129, aNaN},
-                                           {inf, aNaN},
-                                           {aNaN, aNaN},
-                                           {0.0, sNaN},
-                                           {2.0, sNaN},
-                                           {0x1.0p-129, sNaN},
-                                           {inf, sNaN},
-                                           {sNaN, sNaN}};
-
-    for (int i = 0; i < N; ++i) {
-      InType x = INPUTS[i].x;
-      InType y = INPUTS[i].y;
-      ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i],
-                                     func(x, y), 0.5);
-    }
-  }
-
-  void testNormalRange(FMulFunc func) {
-    using FPBits = LIBC_NAMESPACE::fputil::FPBits<InType>;
-    using StorageType = typename FPBits::StorageType;
-    static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
-    static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
-
-    constexpr StorageType COUNT = 10'001;
-    constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
-    for (int signs = 0; signs < 4; ++signs) {
-      for (StorageType v = MIN_NORMAL, w = MAX_NORMAL;
-           v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) {
-        InType x = FPBits(v).get_val(), y = FPBits(w).get_val();
-        if (signs % 2 == 1) {
-          x = -x;
-        }
-        if (signs >= 2) {
-          y = -y;
-        }
-
-        mpfr::BinaryInput<InType> input{x, y};
-        ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, input, func(x, y),
-                                       0.5);
-      }
-    }
-  }
-};
-
-#define LIST_FMUL_MPFR_TESTS(OutType, InType, func)                            \
-  using LlvmLibcFmulTest = FmulMPFRTest<OutType, InType>;                      \
-  TEST_F(LlvmLibcFmulTest, MulMpfr) { testFMulMPFR(&func); }                   \
-  TEST_F(LlvmLibcFmulTest, NanInfMpfr) { testSpecialInputsMPFR(&func); }       \
-  TEST_F(LlvmLibcFmulTest, NormalRange) { testNormalRange(&func); }
-
-#endif // LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H

diff  --git a/libc/test/src/math/MulTest.h b/libc/test/src/math/MulTest.h
new file mode 100644
index 0000000000000..cb81a795be36b
--- /dev/null
+++ b/libc/test/src/math/MulTest.h
@@ -0,0 +1,95 @@
+//===-- Utility class to test 
diff erent flavors of float mul ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TEST_SRC_MATH_MULTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_MULTEST_H
+
+#include "src/stdlib/rand.h"
+#include "src/stdlib/srand.h"
+#include "test/UnitTest/FEnvSafeTest.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+template <typename OutType, typename InType>
+class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+
+  struct InConstants {
+    DECLARE_SPECIAL_CONSTANTS(InType)
+  };
+
+  using InFPBits = typename InConstants::FPBits;
+  using InStorageType = typename InConstants::StorageType;
+
+  static constexpr InStorageType IN_MAX_NORMAL_U =
+      InFPBits::max_normal().uintval();
+  static constexpr InStorageType IN_MIN_NORMAL_U =
+      InFPBits::min_normal().uintval();
+  static constexpr InStorageType IN_MAX_SUBNORMAL_U =
+      InFPBits::max_subnormal().uintval();
+  static constexpr InStorageType IN_MIN_SUBNORMAL_U =
+      InFPBits::min_subnormal().uintval();
+
+  InStorageType get_random_bit_pattern() {
+    InStorageType bits{0};
+    for (InStorageType i = 0; i < sizeof(InStorageType) / 2; ++i)
+      bits = (bits << 2) + static_cast<uint16_t>(LIBC_NAMESPACE::rand());
+    return bits;
+  }
+
+public:
+  using MulFunc = OutType (*)(InType, InType);
+
+  void test_subnormal_range(MulFunc func) {
+    constexpr InStorageType COUNT = 10'001;
+    constexpr InStorageType STEP =
+        (IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) / COUNT;
+    LIBC_NAMESPACE::srand(1);
+    for (int signs = 0; signs < 4; signs++) {
+      for (InStorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+        InType x = InFPBits(get_random_bit_pattern()).get_val();
+        InType y = InFPBits(v).get_val();
+        if ((signs & 1) != 0)
+          x = -x;
+        if ((signs & 2) != 0)
+          y = -y;
+        mpfr::BinaryInput<InType> input{x, y};
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Mul, input, func(x, y),
+                                       0.5);
+      }
+    }
+  }
+
+  void test_normal_range(MulFunc func) {
+    constexpr InStorageType COUNT = 10'001;
+    constexpr InStorageType STEP = (IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT;
+    LIBC_NAMESPACE::srand(1);
+    for (int signs = 0; signs < 4; signs++) {
+      for (InStorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+        InType x = InFPBits(get_random_bit_pattern()).get_val();
+        InType y = InFPBits(v).get_val();
+        if ((signs & 1) != 0)
+          x = -x;
+        if ((signs & 2) != 0)
+          y = -y;
+        mpfr::BinaryInput<InType> input{x, y};
+        EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Mul, input, func(x, y),
+                                       0.5);
+      }
+    }
+  }
+};
+
+#define LIST_MUL_TESTS(OutType, InType, func)                                  \
+  using LlvmLibcMulTest = MulTest<OutType, InType>;                            \
+  TEST_F(LlvmLibcMulTest, SubnormalRange) { test_subnormal_range(&func); }     \
+  TEST_F(LlvmLibcMulTest, NormalRange) { test_normal_range(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_MULTEST_H

diff  --git a/libc/test/src/math/dmull_test.cpp b/libc/test/src/math/dmull_test.cpp
new file mode 100644
index 0000000000000..1b9c9c2c24ed3
--- /dev/null
+++ b/libc/test/src/math/dmull_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for dmull -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/dmull.h"
+
+LIST_MUL_TESTS(double, long double, LIBC_NAMESPACE::dmull)

diff  --git a/libc/test/src/math/f16mul_test.cpp b/libc/test/src/math/f16mul_test.cpp
new file mode 100644
index 0000000000000..49b443870c483
--- /dev/null
+++ b/libc/test/src/math/f16mul_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mul ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mul.h"
+
+LIST_MUL_TESTS(float16, double, LIBC_NAMESPACE::f16mul)

diff  --git a/libc/test/src/math/f16mulf_test.cpp b/libc/test/src/math/f16mulf_test.cpp
new file mode 100644
index 0000000000000..bf2530863621d
--- /dev/null
+++ b/libc/test/src/math/f16mulf_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mulf ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mulf.h"
+
+LIST_MUL_TESTS(float16, float, LIBC_NAMESPACE::f16mulf)

diff  --git a/libc/test/src/math/f16mull_test.cpp b/libc/test/src/math/f16mull_test.cpp
new file mode 100644
index 0000000000000..5292ddb87b7f4
--- /dev/null
+++ b/libc/test/src/math/f16mull_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mull ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mull.h"
+
+LIST_MUL_TESTS(float16, long double, LIBC_NAMESPACE::f16mull)

diff  --git a/libc/test/src/math/fmul_test.cpp b/libc/test/src/math/fmul_test.cpp
index 16eaa1a818daf..3f6df66456bac 100644
--- a/libc/test/src/math/fmul_test.cpp
+++ b/libc/test/src/math/fmul_test.cpp
@@ -1,13 +1,13 @@
-//===-- Unittests for fmul-------------------------------------------------===//
+//===-- Unittests for fmul ------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-//===---------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
 
-#include "FMulTest.h"
+#include "MulTest.h"
 
 #include "src/math/fmul.h"
 
-LIST_FMUL_MPFR_TESTS(float, double, LIBC_NAMESPACE::fmul)
+LIST_MUL_TESTS(float, double, LIBC_NAMESPACE::fmul)

diff  --git a/libc/test/src/math/fmull_test.cpp b/libc/test/src/math/fmull_test.cpp
new file mode 100644
index 0000000000000..ef694063f20dc
--- /dev/null
+++ b/libc/test/src/math/fmull_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for fmull -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/fmull.h"
+
+LIST_MUL_TESTS(float, long double, LIBC_NAMESPACE::fmull)

diff  --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 76d5919ad9156..c57aa9638ed30 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -2531,10 +2531,27 @@ add_fp_unittest(
   SRCS
     fmul_test.cpp
   HDRS
-    FMulTest.h
+    MulTest.h
   DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
     libc.src.math.fmul
-    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  fmull_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    fmull_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.math.fmull
 )
 
 add_fp_unittest(
@@ -3981,3 +3998,78 @@ add_fp_unittest(
   DEPENDS
     libc.src.math.cbrt
 )
+
+add_fp_unittest(
+  dmull_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    dmull_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.math.dmull
+)
+
+add_fp_unittest(
+  f16mul_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    f16mul_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.math.f16mul
+)
+
+add_fp_unittest(
+  f16mulf_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    f16mulf_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.math.f16mulf
+)
+
+add_fp_unittest(
+  f16mull_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    f16mull_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.math.f16mull
+)
+
+add_fp_unittest(
+  f16mulf128_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    f16mulf128_test.cpp
+  HDRS
+    MulTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.basic_operations
+    libc.src.math.f16mulf128
+)

diff  --git a/libc/test/src/math/smoke/FMulTest.h b/libc/test/src/math/smoke/FMulTest.h
deleted file mode 100644
index 33fb82c8d2da1..0000000000000
--- a/libc/test/src/math/smoke/FMulTest.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//===-- Utility class to test fmul[f|l] ---------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_FMULTEST_H
-#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_FMULTEST_H
-
-#include "test/UnitTest/FEnvSafeTest.h"
-#include "test/UnitTest/FPMatcher.h"
-#include "test/UnitTest/Test.h"
-
-template <typename T, typename R>
-class FmulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
-
-  DECLARE_SPECIAL_CONSTANTS(T)
-
-public:
-  typedef T (*FMulFunc)(R, R);
-
-  void testMul(FMulFunc func) {
-
-    EXPECT_FP_EQ_ALL_ROUNDING(T(15.0), func(3.0, 5.0));
-    EXPECT_FP_EQ_ALL_ROUNDING(T(0x1.0p-130), func(0x1.0p1, 0x1.0p-131));
-    EXPECT_FP_EQ_ALL_ROUNDING(T(0x1.0p-127), func(0x1.0p2, 0x1.0p-129));
-    EXPECT_FP_EQ_ALL_ROUNDING(T(1.0), func(1.0, 1.0));
-
-    EXPECT_FP_EQ_ALL_ROUNDING(T(0.0), func(-0.0, -0.0));
-    EXPECT_FP_EQ_ALL_ROUNDING(T(-0.0), func(0.0, -0.0));
-    EXPECT_FP_EQ_ALL_ROUNDING(T(-0.0), func(-0.0, 0.0));
-
-    EXPECT_FP_EQ_ROUNDING_NEAREST(inf, func(0x1.0p100, 0x1.0p100));
-    EXPECT_FP_EQ_ROUNDING_UPWARD(inf, func(0x1.0p100, 0x1.0p100));
-    EXPECT_FP_EQ_ROUNDING_DOWNWARD(max_normal, func(0x1.0p100, 0x1.0p100));
-    EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO(max_normal, func(0x1.0p100, 0x1.0p100));
-
-    EXPECT_FP_EQ_ROUNDING_NEAREST(
-        0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-    EXPECT_FP_EQ_ROUNDING_DOWNWARD(
-        0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-    EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO(
-        0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-    EXPECT_FP_EQ_ROUNDING_UPWARD(
-        0x1p0, func(1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-
-    EXPECT_FP_EQ_ROUNDING_NEAREST(
-        0x1.0p-128f + 0x1.0p-148f,
-        func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-    EXPECT_FP_EQ_ROUNDING_UPWARD(
-        0x1.0p-128f + 0x1.0p-148f,
-        func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-    EXPECT_FP_EQ_ROUNDING_DOWNWARD(
-        0x1.0p-128f + 0x1.0p-149f,
-        func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-    EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO(
-        0x1.0p-128f + 0x1.0p-149f,
-        func(1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150));
-  }
-
-  void testSpecialInputs(FMulFunc func) {
-    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf, 0x1.0p-129));
-    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(0x1.0p-129, inf));
-    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf, 2.0));
-    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(3.0, inf));
-    EXPECT_FP_EQ_ALL_ROUNDING(0.0, func(0.0, 0.0));
-
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(neg_inf, aNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN, neg_inf));
-    EXPECT_FP_EQ_ALL_ROUNDING(inf, func(neg_inf, neg_inf));
-
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, neg_inf));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(neg_inf, 0.0));
-
-    EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(neg_inf, 1.0));
-    EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(1.0, neg_inf));
-
-    EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(neg_inf, 0x1.0p-129));
-    EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(0x1.0p-129, neg_inf));
-
-    EXPECT_FP_EQ_ALL_ROUNDING(0.0, func(0.0, 0x1.0p-129));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(inf, 0.0));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, inf));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, aNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(2.0, aNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0x1.0p-129, aNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(inf, aNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN, aNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0.0, sNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(2.0, sNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(0x1.0p-129, sNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(inf, sNaN));
-    EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(sNaN, sNaN));
-  }
-};
-
-#define LIST_FMUL_TESTS(T, R, func)                                            \
-  using LlvmLibcFmulTest = FmulTest<T, R>;                                     \
-  TEST_F(LlvmLibcFmulTest, Mul) { testMul(&func); }                            \
-  TEST_F(LlvmLibcFmulTest, NaNInf) { testSpecialInputs(&func); }
-
-#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_FMULTEST_H

diff  --git a/libc/test/src/math/smoke/MulTest.h b/libc/test/src/math/smoke/MulTest.h
new file mode 100644
index 0000000000000..e2298eaeeb216
--- /dev/null
+++ b/libc/test/src/math/smoke/MulTest.h
@@ -0,0 +1,171 @@
+//===-- Utility class to test 
diff erent flavors of float mul ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/FPUtil/BasicOperations.h"
+#include "test/UnitTest/FEnvSafeTest.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+template <typename OutType, typename InType>
+class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+
+  DECLARE_SPECIAL_CONSTANTS(OutType)
+
+  struct InConstants {
+    DECLARE_SPECIAL_CONSTANTS(InType)
+  };
+
+  using InFPBits = typename InConstants::FPBits;
+  using InStorageType = typename InConstants::StorageType;
+
+  InConstants in;
+
+public:
+  using MulFunc = OutType (*)(InType, InType);
+
+  void test_special_numbers(MulFunc func) {
+    EXPECT_FP_IS_NAN(func(aNaN, aNaN));
+    EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
+
+    InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
+    EXPECT_FP_EQ(InType(0x42.0p+0),
+                 LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, zero)));
+    EXPECT_FP_EQ(InType(0x42.0p+0),
+                 LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_42)));
+
+    if constexpr (sizeof(OutType) < sizeof(InType)) {
+      InStorageType max_payload = InFPBits::FRACTION_MASK >> 1;
+      InType qnan_max = InFPBits::quiet_nan(Sign::POS, max_payload).get_val();
+      EXPECT_FP_EQ(zero,
+                   LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, zero)));
+      EXPECT_FP_EQ(zero,
+                   LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_max)));
+      EXPECT_FP_EQ(InType(0x42.0p+0),
+                   LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, qnan_42)));
+      EXPECT_FP_EQ(InType(0x42.0p+0),
+                   LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, qnan_max)));
+    }
+
+    EXPECT_FP_EQ(inf, func(inf, InType(1.0)));
+    EXPECT_FP_EQ(neg_inf, func(neg_inf, InType(1.0)));
+    EXPECT_FP_EQ(neg_inf, func(inf, InType(-1.0)));
+    EXPECT_FP_EQ(inf, func(neg_inf, InType(-1.0)));
+
+    EXPECT_FP_EQ_ALL_ROUNDING(zero, func(zero, zero));
+    EXPECT_FP_EQ_ALL_ROUNDING(zero, func(neg_zero, neg_zero));
+    EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(zero, neg_zero));
+    EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(neg_zero, zero));
+
+    EXPECT_FP_EQ_ALL_ROUNDING(OutType(1.0), func(1.0, 1.0));
+    EXPECT_FP_EQ_ALL_ROUNDING(OutType(15.0), func(3.0, 5.0));
+    EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-13), func(0x1.0p+1, 0x1.0p-14));
+    EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-10), func(0x1.0p+2, 0x1.0p-12));
+  }
+
+  void test_invalid_operations(MulFunc func) {
+    EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, zero), FE_INVALID);
+    EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_zero), FE_INVALID);
+    EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, zero), FE_INVALID);
+    EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_zero), FE_INVALID);
+  }
+
+  void test_range_errors(MulFunc func) {
+    using namespace LIBC_NAMESPACE::fputil::testing;
+
+    if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+
+      EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
+                                  func(in.neg_min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+    }
+
+    if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
+                                  func(neg_max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+
+      EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
+                                  func(in.neg_min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+    }
+
+    if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+
+      EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal,
+                                  func(in.neg_min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+    }
+
+    if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
+      EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
+                                  func(neg_max_normal, max_normal),
+                                  FE_OVERFLOW | FE_INEXACT);
+
+      EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
+                                  func(in.min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+      EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
+                                  func(in.neg_min_denormal, in.min_denormal),
+                                  FE_UNDERFLOW | FE_INEXACT);
+      EXPECT_MATH_ERRNO(ERANGE);
+    }
+  }
+
+  void test_inexact_results(MulFunc func) {
+    InFPBits x_bits = InFPBits::one();
+    x_bits.set_mantissa(InFPBits::SIG_MASK);
+    InType x = x_bits.get_val();
+    func(x, x);
+    EXPECT_FP_EXCEPTION(FE_INEXACT);
+  }
+};
+
+#define LIST_MUL_TESTS(OutType, InType, func)                                  \
+  using LlvmLibcMulTest = MulTest<OutType, InType>;                            \
+  TEST_F(LlvmLibcMulTest, SpecialNumbers) { test_special_numbers(&func); }     \
+  TEST_F(LlvmLibcMulTest, InvalidOperations) {                                 \
+    test_invalid_operations(&func);                                            \
+  }                                                                            \
+  TEST_F(LlvmLibcMulTest, RangeErrors) { test_range_errors(&func); }           \
+  TEST_F(LlvmLibcMulTest, InexactResults) { test_inexact_results(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H

diff  --git a/libc/test/src/math/smoke/dmulf128_test.cpp b/libc/test/src/math/smoke/dmulf128_test.cpp
new file mode 100644
index 0000000000000..2ee2d10b9a19b
--- /dev/null
+++ b/libc/test/src/math/smoke/dmulf128_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for dmulf128 --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/dmulf128.h"
+
+LIST_MUL_TESTS(double, float128, LIBC_NAMESPACE::dmulf128)

diff  --git a/libc/test/src/math/smoke/dmull_test.cpp b/libc/test/src/math/smoke/dmull_test.cpp
new file mode 100644
index 0000000000000..1b9c9c2c24ed3
--- /dev/null
+++ b/libc/test/src/math/smoke/dmull_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for dmull -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/dmull.h"
+
+LIST_MUL_TESTS(double, long double, LIBC_NAMESPACE::dmull)

diff  --git a/libc/test/src/math/smoke/f16mul_test.cpp b/libc/test/src/math/smoke/f16mul_test.cpp
new file mode 100644
index 0000000000000..49b443870c483
--- /dev/null
+++ b/libc/test/src/math/smoke/f16mul_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mul ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mul.h"
+
+LIST_MUL_TESTS(float16, double, LIBC_NAMESPACE::f16mul)

diff  --git a/libc/test/src/math/smoke/f16mulf128_test.cpp b/libc/test/src/math/smoke/f16mulf128_test.cpp
new file mode 100644
index 0000000000000..46e52cf068a7b
--- /dev/null
+++ b/libc/test/src/math/smoke/f16mulf128_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mulf128 ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mulf128.h"
+
+LIST_MUL_TESTS(float16, float128, LIBC_NAMESPACE::f16mulf128)

diff  --git a/libc/test/src/math/smoke/f16mulf_test.cpp b/libc/test/src/math/smoke/f16mulf_test.cpp
new file mode 100644
index 0000000000000..bf2530863621d
--- /dev/null
+++ b/libc/test/src/math/smoke/f16mulf_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mulf ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mulf.h"
+
+LIST_MUL_TESTS(float16, float, LIBC_NAMESPACE::f16mulf)

diff  --git a/libc/test/src/math/smoke/f16mull_test.cpp b/libc/test/src/math/smoke/f16mull_test.cpp
new file mode 100644
index 0000000000000..5292ddb87b7f4
--- /dev/null
+++ b/libc/test/src/math/smoke/f16mull_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for f16mull ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/f16mull.h"
+
+LIST_MUL_TESTS(float16, long double, LIBC_NAMESPACE::f16mull)

diff  --git a/libc/test/src/math/smoke/fmul_test.cpp b/libc/test/src/math/smoke/fmul_test.cpp
index 0eb664f7411ee..3f6df66456bac 100644
--- a/libc/test/src/math/smoke/fmul_test.cpp
+++ b/libc/test/src/math/smoke/fmul_test.cpp
@@ -1,13 +1,13 @@
-//===-- Unittests for fmul-------------------------------------------------===//
+//===-- Unittests for fmul ------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-//===---------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
 
-#include "FMulTest.h"
+#include "MulTest.h"
 
 #include "src/math/fmul.h"
 
-LIST_FMUL_TESTS(float, double, LIBC_NAMESPACE::fmul)
+LIST_MUL_TESTS(float, double, LIBC_NAMESPACE::fmul)

diff  --git a/libc/test/src/math/smoke/fmulf128_test.cpp b/libc/test/src/math/smoke/fmulf128_test.cpp
new file mode 100644
index 0000000000000..37c8d1cf9908d
--- /dev/null
+++ b/libc/test/src/math/smoke/fmulf128_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for fmulf128 --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/fmulf128.h"
+
+LIST_MUL_TESTS(float, float128, LIBC_NAMESPACE::fmulf128)

diff  --git a/libc/test/src/math/smoke/fmull_test.cpp b/libc/test/src/math/smoke/fmull_test.cpp
new file mode 100644
index 0000000000000..ef694063f20dc
--- /dev/null
+++ b/libc/test/src/math/smoke/fmull_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for fmull -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MulTest.h"
+
+#include "src/math/fmull.h"
+
+LIST_MUL_TESTS(float, long double, LIBC_NAMESPACE::fmull)

diff  --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index b67a9da40bd7b..bb63e0b9f4de0 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -539,7 +539,7 @@ class MPFRNumber {
     return result;
   }
 
-  MPFRNumber fmul(const MPFRNumber &b) {
+  MPFRNumber mul(const MPFRNumber &b) {
     MPFRNumber result(*this);
     mpfr_mul(result.value, value, b.value, mpfr_rounding);
     return result;
@@ -800,12 +800,12 @@ binary_operation_one_output(Operation op, InputType x, InputType y,
     return inputX.fmod(inputY);
   case Operation::Hypot:
     return inputX.hypot(inputY);
+  case Operation::Mul:
+    return inputX.mul(inputY);
   case Operation::Pow:
     return inputX.pow(inputY);
   case Operation::Sub:
     return inputX.sub(inputY);
-  case Operation::Fmul:
-    return inputX.fmul(inputY);
   default:
     __builtin_unreachable();
   }
@@ -1013,15 +1013,18 @@ void explain_binary_operation_one_output_error(
 template void
 explain_binary_operation_one_output_error(Operation, const BinaryInput<float> &,
                                           float, double, RoundingMode);
+template void explain_binary_operation_one_output_error(
+    Operation, const BinaryInput<double> &, float, double, RoundingMode);
 template void explain_binary_operation_one_output_error(
     Operation, const BinaryInput<double> &, double, double, RoundingMode);
+template void explain_binary_operation_one_output_error(
+    Operation, const BinaryInput<long double> &, float, double, RoundingMode);
+template void explain_binary_operation_one_output_error(
+    Operation, const BinaryInput<long double> &, double, double, RoundingMode);
 template void
 explain_binary_operation_one_output_error(Operation,
                                           const BinaryInput<long double> &,
                                           long double, double, RoundingMode);
-
-template void explain_binary_operation_one_output_error(
-    Operation, const BinaryInput<double> &, float, double, RoundingMode);
 #ifdef LIBC_TYPES_HAS_FLOAT16
 template void explain_binary_operation_one_output_error(
     Operation, const BinaryInput<float16> &, float16, double, RoundingMode);
@@ -1195,6 +1198,12 @@ template bool compare_binary_operation_one_output(Operation,
                                                   const BinaryInput<double> &,
                                                   double, double, RoundingMode);
 template bool
+compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
+                                    float, double, RoundingMode);
+template bool
+compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
+                                    double, double, RoundingMode);
+template bool
 compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
                                     long double, double, RoundingMode);
 

diff  --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index 28390af9ee6d8..8d51fa4e47726 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -79,9 +79,9 @@ enum class Operation : int {
   Div,
   Fmod,
   Hypot,
+  Mul,
   Pow,
   Sub,
-  Fmul,
   EndBinaryOperationsSingleOutput,
 
   // Operations which take two floating point numbers of the same type as


        


More information about the libc-commits mailing list