You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Apple Silicon平台下如何将非规格化数刷新为零?

Apple Silicon平台下如何将非规格化数刷新为零?

你好!我刚好做过类似的实时音频插件移植工作,非常理解你对非规格化数(denormal)性能问题的顾虑——这些极小的数会触发软件处理路径,对实时音频的延迟影响确实很大。下面针对你的问题逐一解答:

首先明确:Apple Silicon 是不是等于 ARM?

Apple Silicon(M1/M2/M3系列)确实是基于ARMv8.5-A及以上版本的定制架构实现,完全遵循ARM的应用级浮点规范,所以ARM文档里的浮点控制逻辑完全适用于苹果的芯片。不过苹果会在基础架构上做一些定制优化,但核心的浮点控制寄存器行为是和标准ARM一致的。

核心问题:Apple Silicon 上等价于 FTZ/DAZ 的实现

Intel的_MM_SET_FLUSH_ZERO_MODE_MM_SET_DENORMALS_ZERO_MODE,对应ARM架构里的FPCR(浮点控制寄存器)的FZ和DZ位

  • FZ位(第24位):开启后,所有浮点运算的结果如果是非规格化数,会直接刷新为零(对应Intel的FTZ);
  • DZ位(第25位):开启后,所有输入的非规格化数会被当作零来处理(对应Intel的DAZ)。

默认行为说明

和x86平台不同,Apple Silicon默认是不开启这两个位的——也就是会保留非规格化数,所以你必须手动设置才能获得和Intel平台FTZ+DAZ一致的行为。

具体实现代码(C/C++,Clang编译器)

苹果的Clang编译器提供了内置函数来直接读写FPCR寄存器,不需要用复杂的内联汇编,非常方便。而且必须注意:实时音频插件不能全局修改浮点状态后不恢复,否则会影响宿主或其他插件的正常运行,所以一定要保存原状态并在处理完成后恢复:

#include <stdint.h>

// 在音频处理前保存当前的浮点控制寄存器状态
uint64_t original_fpcr = __builtin_arm_get_fpcr();

// 开启FZ(Flush to Zero)和DZ(Denormals as Zero)位
// FZ是第24位,DZ是第25位,用位或操作设置
uint64_t new_fpcr = original_fpcr | (1ULL << 24) | (1ULL << 25);
__builtin_arm_set_fpcr(new_fpcr);

// ---------------------------
// 这里执行你的实时音频处理逻辑
// ---------------------------

// 处理完成后,必须恢复原来的浮点控制寄存器状态
__builtin_arm_set_fpcr(original_fpcr);

补充说明

  1. 这个设置对NEON指令集(ARM的SIMD,对应Intel的SSE/AVX)同样生效,你的音频处理里如果用了NEON优化,非规格化数也会被正确刷新为零;
  2. 如果你用的是Accelerate框架做音频处理,这个FPCR设置也会作用于框架内的浮点运算;
  3. 务必确保在插件的音频处理线程内做这个设置,不要在主线程修改,避免线程间的状态冲突。

备注:内容来源于stack exchange,提问作者Sjoerd van Kreel

火山引擎 最新活动