LMMS
Loading...
Searching...
No Matches
Hardware.h
Go to the documentation of this file.
1/*
2 * Hardware.h - This file contains useful tools that are hardware-
3 * dependent, such as cache-line size and busy-wait hints.
4 *
5 * Copyright (c) 2026 Fawn Sannar <rubiefawn/at/gmail.com>
6 *
7 * This file is part of LMMS - https://lmms.io
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifndef LMMS_HARDWARE_H
25#define LMMS_HARDWARE_H
26
27#include <cstdint>
28#include <new>
29#if __cpp_lib_hardware_interference_size >= 201703L
30 #if defined(__GNUG__) && !defined(__clang__)
31 // https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Winterference-size
32 #pragma GCC diagnostic ignored "-Winterference-size"
33 #endif
34#endif
35#include "lmmsconfig.h"
36#if defined(LMMS_HOST_X86_64) || defined(LMMS_HOST_X86)
37 #include <immintrin.h>
38#elif defined(LMMS_HOST_ARM64) || defined(LMMS_HOST_ARM32)
39 #if defined(__ARM_ACLE)
40 #include <arm_acle.h>
41 #elif defined(_MSC_VER)
42 #include <intrin.h>
43 #elif defined(__GNUG__) // HACK: Remove this once GCC properly provides __ARM_ACLE
44 #if defined(LMMS_HOST_ARM64)
45 // https://developer.arm.com/documentation/ddi0602/2026-03/Base-Instructions/ISB--Instruction-synchronization-barrier-
46 // The parameter is ignored since 15 is the only valid value
47 inline void __isb(unsigned int) { asm volatile ("isb 15" ::: "memory"); }
48 #elif defined(LMMS_HOST_ARM32)
49 inline void __yield() { asm volatile ("yield"); }
50 #endif
51 #endif
52#endif
53
54namespace lmms
55{
56
60inline constexpr std::size_t hardware_destructive_interference_size =
61#if __cpp_lib_hardware_interference_size >= 201703L
62 std::hardware_destructive_interference_size;
63#elif defined(LMMS_HOST_X86_64) || defined(LMMS_HOST_X86)
64 64;
65#elif defined(LMMS_HOST_ARM64)
66 256;
67#elif defined(LMMS_HOST_ARM32)
68 64;
69#elif defined(LMMS_HOST_RISCV64) || defined(LMMS_HOST_RISCV32)
70 64;
71#elif defined(LMMS_HOST_PPC64)
72 128;
73#elif defined(LMMS_HOST_PPC32)
74 32;
75#else
76 64;
77 #warning Defaulting to 64 for lmms::hardware_destructive_interference_size for this architecture. This may be incorrect.
78#endif
79
80
81
89inline void busyWaitHint()
90{
91#if defined(LMMS_HOST_X86_64) || defined(LMMS_HOST_X86)
92 _mm_pause();
93#elif defined(LMMS_HOST_ARM64)
94 __isb(15);
95#elif defined(LMMS_HOST_ARM32)
96 __yield();
97#elif defined(LMMS_HOST_RISCV64) || defined(LMMS_HOST_RISCV32)
98 asm volatile ("pause");
99#else
100 // TODO LMMS_HOST_PPC*
101 #warning lmms::busyWaitHint() is not implemented on this architecture and will have no effect. Performance may suffer.
102#endif
103}
104
105
106
113inline void disableDenormals()
114{
115#if defined(LMMS_HOST_X86_64) || defined(LMMS_HOST_X86)
116 // https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
117 // IntelĀ® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture
118 // 11.6.3 Checking for the DAZ Flag in the MXCSR Register
119 unsigned int flags = 0x8000; // FTZ
120 alignas(16) std::uint8_t buf[512] = {0};
121 #if defined(LMMS_HOST_X86_64)
122 _fxsave64(buf);
123 #elif defined(LMMS_HOST_X86)
124 _fxsave(buf);
125 #endif
126 flags |= buf[28] & 0x0040; // DAZ if supported
127 _mm_setcsr(_mm_getcsr() | flags);
128#elif defined(LMMS_HOST_ARM64) || defined(LMMS_HOST_ARM32)
129 constexpr auto FZ = 1 << 24; // Flushing denormalized numbers to zero control bit
130 #if defined(_MSC_VER) && defined(LMMS_HOST_ARM64)
131 // https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
132 // 0x5a20 == ARM64_SYSREG(0b11, 0b011, 0b0100, 0b0100, 0b000)
133 _WriteStatusReg(0x5a20, _ReadStatusReg(0x5a20) | FZ);
134 #elif defined(_MSC_VER) && defined(LMMS_HOST_ARM32)
135 // https://learn.microsoft.com/en-us/windows/arm/arm32-to-arm64
136 // https://learn.microsoft.com/en-us/windows/whats-new/deprecated-features
137 #warning MSVC for ARM32 is deprecated. lmms::disableDenormals() is not implemented and will have no effect.
138 #elif defined(LMMS_HOST_ARM64)
139 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch64-Registers/FPCR--Floating-point-Control-Register
140 std::uint64_t fpcr;
141 asm volatile ("mrs %0, fpcr" : "=r" (fpcr));
142 asm volatile ("msr fpcr, %0" :: "ri" (fpcr | FZ));
143 #elif defined(LMMS_HOST_ARM32)
144 // https://developer.arm.com/documentation/ddi0601/2026-03/AArch32-Registers/FPSCR--Floating-Point-Status-and-Control-Register
145 std::uint32_t fpscr;
146 asm volatile ("vmrs %0, fpscr" : "=r" (fpscr));
147 asm volatile ("vmsr fpscr, %0" :: "ri" (fpscr | FZ));
148 #endif
149#else
150 // TODO LMMS_HOST_RISCV*: https://docs.riscv.org/reference/isa/unpriv/f-st-ext.html
151 // As of v2.2 of both the F and D extensions, there appears to be no
152 // way to flush denormals to zero. This may change in the future.
153 // TODO LMMS_HOST_PPC*: https://openpowerfoundation.org/specifications/isa
154 // This is possible for SIMD instructions by setting bit 111 of the
155 // VSCR register (a.k.a. the "NJ" flag), but there doesn't appear to
156 // be an equivalent for scalar instructions?
157 #warning lmms::disableDenormals() is not implemented on this architecture and will have no effect. Performance may suffer.
158#endif
159}
160
161} // namespace lmms
162
163#endif // LMMS_HARDWARE_H
Definition AudioAlsa.cpp:35
void busyWaitHint()
Platform-dependent hint to the processor that it is in a busy-wait loop. This helps optimize spinlock...
Definition Hardware.h:89
void disableDenormals()
Disable IEEE 754 denormals on the current thread.
Definition Hardware.h:113
constexpr std::size_t hardware_destructive_interference_size
Platform-dependent minimum amount of padding between objects to prevent false cache sharing.
Definition Hardware.h:60