Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
scoped_flush_denormals.hpp File Reference

Hardware flush-to-zero RAII guard for the audio callback boundary. More...

#include <cstdint>

Go to the source code of this file.

Classes

class  pulp::signal::ScopedFlushDenormals

Namespaces

namespace  pulp
namespace  pulp::signal
namespace  pulp::signal::detail
 Round-2 effect-wave vocabulary.

Functions

bool pulp::signal::denormals_are_flushed () noexcept

Variables

constexpr bool pulp::signal::kHardwareFlushSupported = false
 True when this build sets the hardware flush-to-zero mode.

Detailed Description

Hardware flush-to-zero RAII guard for the audio callback boundary.

Denormal (subnormal) floating-point values cause severe CPU stalls when they enter recursive DSP state — IIR/SVF filter memory, reverb and delay feedback, envelope tails. pulp::signal::snap_to_zero (denormal.hpp) fixes this per-value where DSP opts in, but it cannot protect code that forgets to call it. ScopedFlushDenormals sets the CPU's flush-to-zero mode for the lifetime of the scope so every operation flushes denormal results to zero, then restores the caller's previous mode on exit.

Wrap the audio callback body (alongside runtime::ScopedNoAlloc):

void process(...) {
// ... DSP ...
}
Definition scoped_flush_denormals.hpp:106

This is part of Pulp's numeric-mode policy; see docs/guides/dsp-threading.md ("Numeric mode: denormals & determinism").

Intended usage: wrap the audio callback boundary — a region whose body is an opaque function call such as Processor::process(). Setting the FP mode is not a compiler reordering barrier for FP arithmetic, so do not rely on it around arbitrary inline DSP in the same function; the compiler may schedule such arithmetic across the mode change. An opaque call in between (the normal case) prevents that hoisting. For inline recursive math, use snap_to_zero (denormal.hpp) instead/as well.

Platform coverage:

  • x86-64 (SSE2): sets MXCSR FTZ (flush denormal results to zero). FTZ is universal on SSE and cannot fault. DAZ (treat denormal inputs as zero) is intentionally NOT set: it is only valid when MXCSR_MASK bit 6 reports support (Intel says writing an unsupported MXCSR bit can #GP), so enabling it portably needs an FXSAVE/MXCSR_MASK probe. FTZ alone fixes the dominant recursive-feedback denormal stall; for denormal inputs use snap_to_zero. 32-bit x86 uses the no-op fallback.
  • AArch64 (Apple Silicon, ARM64 Linux/Android) under GCC/Clang: sets FPCR.FZ (bit 24). FZ flushes denormal results, and also inputs in the default FPCR.AH=0 mode; under FPCR.AH=1 it is result-flush only. Treat the AArch64 guard as result-flush, not a guaranteed input-DAZ.
  • Anything else (e.g. MSVC/ARM64, 32-bit x86): a no-op guard — correct, just without hardware acceleration. DSP should still call snap_to_zero in recursive paths regardless of this guard.