🍑 nectarine
Audio synthesis tools for C23
Toggle main menu visibility
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
27
static
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
84
static
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
}
nec_disable_denormals
static void nec_disable_denormals(void)
Disable IEEE 754 denormals on the current thread.
Definition
denormals.h:27
nec_enable_denormals
static void nec_enable_denormals(void)
Enable IEEE 754 denormals on the current thread.
Definition
denormals.h:84
denormals.h
Generated by
1.17.0