[libc] [llvm] [libc][fenv] Refactor x86 fenv implementations to make it work for various fenv_t. (PR #165015)

via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 9 07:28:16 PST 2025


================
@@ -0,0 +1,166 @@
+//===-- sse2 floating point env manipulation utilities ----------*- 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_X86_64_FENV_MXCSR_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FENV_MXCSR_UTILS_H
+
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/fenv_t.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/FPUtil/x86_64/fenv_x86_common.h"
+#include "src/__support/macros/attributes.h" // LIBC_INLINE
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
+#include "src/__support/macros/properties/compiler.h"
+#include "src/__support/macros/sanitizer.h"
+
+#include <immintrin.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+namespace sse {
+
+using internal::ExceptionFlags;
+using internal::RoundingControl;
+
+// SSE FPU environment from Intel 64 and IA-32 Architectures Software Developer
+// Manuals - Chapter 10
+// https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
+//
+// The SSE floating point environment will be save/load with LDMXCSR/STMXCSR
+// instructions, which will return the following 4-byte structure in 32-bit
+// mode (see section 10.2.3, figure 10-3 in the manual linked above).
+
+// SSE MXCSR register (32-bit) structure: (section 10.2.3 in the manual)
+// - Bit 0: Invalid Exception
+// - Bit 1: Denormal Exception
+// - Bit 2: Division-by-zero Exception
+// - Bit 3: Overflow Exception
+// - Bit 4: Underflow Exception
+// - Bit 5: Inexact Exception
+// - Bit 6: Denormal Are Zeros (DAZ)
+// - Bit 7: Invalid Exception Mask
+// - Bit 8: Denormal Exception Mask
+// - Bit 9: Division-by-zero Exception Mask
+// - Bit 10: Overflow Exception Mask
+// - Bit 11: Underflow Exception Mask
+// - Bit 12: Inexact Exception Mask
+// - Bit 13-14: Rounding Control
+// - Bit 15: Flush Denormal To Zero (FTZ)
+// - Bit 16-31: Reserved, will raise general-protection exception if set to
+//              non-zero.
+
+LIBC_INLINE static uint32_t get_mxcsr() { return _mm_getcsr(); }
+
+LIBC_INLINE static void write_mxcsr(uint32_t w) { _mm_setcsr(w); }
+
+LIBC_INLINE static void clear_except(uint16_t excepts) {
+  uint32_t mxcsr = _MM_GET_EXCEPTION_STATE();
+  mxcsr &= ~static_cast<uint32_t>(excepts);
+  _MM_SET_EXCEPTION_STATE(mxcsr);
+}
+
+LIBC_INLINE static uint16_t test_except(uint16_t excepts) {
+  uint32_t mxcsr = get_mxcsr();
+  return static_cast<uint16_t>(excepts & mxcsr);
+}
+
+LIBC_INLINE static uint16_t get_except() {
+  uint32_t mxcsr = ~get_mxcsr();
+  return static_cast<uint16_t>(
+      (mxcsr >> ExceptionFlags::MXCSR_EXCEPTION_MASK_BIT_POSITION) &
+      ExceptionFlags::ALL_F);
+}
+
+LIBC_INLINE static void set_except(uint16_t excepts) {
+  _MM_SET_EXCEPTION_STATE(excepts);
+}
+
+LIBC_INLINE static void raise_except(uint16_t excepts) {
+  uint32_t mxcsr = _MM_GET_EXCEPTION_STATE();
+  mxcsr |= excepts;
+  _MM_SET_EXCEPTION_STATE(mxcsr);
+#ifdef LIBC_TRAP_ON_RAISE_FP_EXCEPT
+  // We will try to trigger the SIGFPE if floating point exceptions are not
+  // masked.  Since we already set all the floating point exception flags, we
+  // only need to trigger the trap on one of them.
+  static constexpr float EXCEPTION_INPUTS[6][2] = {
+      // FE_INVALID: 0.0 * inf
+      {0.0f, cpp::bit_cast<float>(0x7f80'0000U)},
+      // FE_DENORM: 1.0 * 0x1.0p-128
+      {1.0f, 0x1.0p-128f},
+      // FE_DIVBYZERO: 1.0 / 0.0
+      {1.0f, 0.0f},
+      // FE_OVERFLOW: 0x1.0p127 * 0x1.0p127
+      {0x1.0p127f, 0x1.0p127f},
+      // FE_UNDERFLOW: 0x1.0p-126 * 0x1.0p-126
+      {0x1.0p-126f, 0x1.0p-126f},
+      // FE_INEXACT: (1 + 2^-12) * (1 + 2^-12)
+      {0x1.001p0f, 0x1.001p0f}};
+
+  uint32_t except_masks =
+      (~(get_mxcsr() >> ExceptionFlags::MXCSR_EXCEPTION_MASK_BIT_POSITION)) &
+      excepts;
+  if (except_masks) {
+    int idx = cpp::countr_zero(except_masks);
+    if (idx == 2) {
+      // FE_DIVBYZERO, we need floating point division operations.
+      [[maybe_unused]] volatile float z = EXCEPTION_INPUTS[idx][0];
+      z /= EXCEPTION_INPUTS[idx][1];
+    } else {
+      // For the remaining exceptions, we floating point multiplications.
----------------
lntue wrote:

Done.

https://github.com/llvm/llvm-project/pull/165015


More information about the llvm-commits mailing list