🍑 nectarine
Audio synthesis tools for C23
Loading...
Searching...
No Matches
denormals.h
Go to the documentation of this file.
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
7#pragma once
8
9#include <stdint.h>
10#if defined(__amd64__) || defined(_M_AMD64) || defined(__i386__) || defined(_M_IX86)
11 #include <immintrin.h>
12#elif defined(_M_ARM64) // MSVC arm64
13 #include <intrin.h>
14#elif defined(_M_ARM) // MSVC arm32
15 #include <float.h>
16#endif
17
27static inline void nec_disable_denormals(void) {
28#if defined(__SSE4_1__)
29 // This version of the function does not check if the processor
30 // supports the "denormals-are-zero" (or "DAZ") flag, and using it
31 // on a processor that does not support DAZ will raise a
32 // general-protection exception. Intel's manual states that DAZ is
33 // "...available in most of the Pentium 4 processors and in the
34 // Intel Xeon processor, with the exception of some early
35 // steppings", but does not specify what those exceptions are.
36 // SSE 4.1 is a conservative estimate. SSE3 might be more accurate,
37 // but the only way to know for sure is to test on actual hardware.
38 _mm_setcsr(_mm_getcsr() | 0x8040); // Set DAZ and FTZ both to 1
39#elif defined(__amd64__) || defined(_M_AMD64) || defined(__i386__) || defined(_M_IX86)
40 // https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
41 // Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture
42 // 11.6.3 Checking for the DAZ Flag in the MXCSR Register
43 unsigned int flags = 0x8000; // FTZ
44 alignas(16) uint8_t buf[512] = {0};
45 #if defined(__amd64__) || defined(_M_AMD64)
46 _fxsave64(buf);
47 #elif defined(__i386__) || defined(_M_IX86)
48 _fxsave(buf);
49 #endif
50 flags |= buf[28] & 0x0040; // DAZ if supported
51 _mm_setcsr(_mm_getcsr() | flags);
52#elif defined(_M_ARM64)
53 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch64-Registers/FPCR--Floating-point-Control-Register
54 // https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
55 // 0x5a20 == ARM64_SYSREG(0b11, 0b011, 0b0100, 0b0100, 0b000)
56 _WriteStatusReg(0x5a20, _ReadStatusReg(0x5a20) | 0x1000000);
57#elif defined(_M_ARM)
58 // WARN: This is untested. MSVC for ARM32 is deprecated.
59 // https://learn.microsoft.com/en-us/windows/arm/arm32-to-arm64
60 // https://learn.microsoft.com/en-us/windows/whats-new/deprecated-features
61 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/control87-controlfp-control87-2
62 _controlfp(0x03000000, 0x1000000); // _MCW_DN, _DN_FLUSH
63#elif defined(__aarch64__)
64 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch64-Registers/FPCR--Floating-point-Control-Register
65 uint64_t fpcr;
66 __asm__ volatile ("mrs %0, fpcr" : "=r" (fpcr));
67 __asm__ volatile ("msr fpcr, %0" :: "ri" (fpcr | 0x1000000));
68#elif defined(__arm__)
69 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch32-Registers/FPSCR--Floating-Point-Status-and-Control-Register
70 uint32_t fpscr;
71 __asm__ volatile ("vmrs %0, fpscr" : "=r" (fpscr));
72 __asm__ volatile ("vmsr fpscr, %0" :: "ri" (fpscr | 0x1000000));
73#else
74 #warning nec_disable_denormals() is not implemented on this architecture and will have no effect.
75#endif
76}
77
84static inline void nec_enable_denormals(void) {
85#if defined(__amd64__) || defined(_M_AMD64) || defined(__i386__) || defined(_M_IX86)
86 _mm_setcsr(_mm_getcsr() & ~0x8040); // Set DAZ and FTZ both to 0
87#elif defined(_M_ARM64)
88 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch64-Registers/FPCR--Floating-point-Control-Register
89 // https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
90 // 0x5a20 == ARM64_SYSREG(0b11, 0b011, 0b0100, 0b0100, 0b000)
91 _WriteStatusReg(0x5a20, _ReadStatusReg(0x5a20) & ~0x1000000);
92#elif defined(_M_ARM)
93 // WARN: This is untested. MSVC for ARM32 is deprecated.
94 // https://learn.microsoft.com/en-us/windows/arm/arm32-to-arm64
95 // https://learn.microsoft.com/en-us/windows/whats-new/deprecated-features
96 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/control87-controlfp-control87-2
97 _controlfp(0x03000000, 0x0000000); // _MCW_DN, _DN_SAVE
98#elif defined(__aarch64__)
99 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch64-Registers/FPCR--Floating-point-Control-Register
100 uint64_t fpcr;
101 __asm__ volatile ("mrs %0, fpcr" : "=r" (fpcr));
102 __asm__ volatile ("msr fpcr, %0" :: "ri" (fpcr & ~0x1000000));
103#elif defined(__arm__)
104 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch32-Registers/FPSCR--Floating-Point-Status-and-Control-Register
105 uint32_t fpscr;
106 __asm__ volatile ("vmrs %0, fpscr" : "=r" (fpscr));
107 __asm__ volatile ("vmsr fpscr, %0" :: "ri" (fpscr & ~0x1000000));
108#else
109 #warning nec_enable_denormals() is not implemented on this architecture and will have no effect.
110#endif
111}
static void nec_disable_denormals(void)
Disable IEEE 754 denormals on the current thread.
Definition denormals.h:27
static void nec_enable_denormals(void)
Enable IEEE 754 denormals on the current thread.
Definition denormals.h:84