You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Arm Neon函数中d8-d15寄存器的溢出操作?

问题

我有一个通过函数指针调用的函数,会用到全部32个Arm Neon寄存器。按照Arm调用约定,该函数需要溢出并恢复d8-d15寄存器的低段部分,但我希望把这个溢出恢复的负担转移到上层函数,避免在该函数内执行此操作。

示例代码(当前实现)

C代码

#include "arm_neon.h"

inline void add(float32x4x4_t &a, float32x4x4_t b) {
    a.val[0] = vaddq_f32(a.val[0], b.val[0]);
    a.val[1] = vaddq_f32(a.val[1], b.val[1]);
    a.val[2] = vaddq_f32(a.val[2], b.val[2]);
    a.val[3] = vaddq_f32(a.val[3], b.val[3]);
}

float32x4x4_t foo(float *input, int n) {
   auto a = vld4q_f32(input); input += 16;
   auto b = vld4q_f32(input); input += 16;
   auto c = vld4q_f32(input); input += 16;
   auto d = vld4q_f32(input); input += 16;
   do {
       add(a, b);
       add(b, c);
       add(c, d);
       add(d, d);
   } while (--n);
   add(a,b);
   add(a,c);
   add(a,d);
   return a;
}

对应汇编输出

foo(float*, int):                              // @foo(float*, int)
        stp     d11, d10, [sp, #-32]!           // 16-byte Folded Spill
        stp     d9, d8, [sp, #16]               // 16-byte Folded Spill
        mov     x9, x0

可以看到编译器自动在foo函数开头插入了d8-d11的溢出操作,符合调用约定要求。

当前尝试的上层处理方式

我可以通过在调用者中插入空汇编指令,强制调用者溢出并恢复所有被调用者保存的Neon寄存器:

C代码

float32x4x4_t bar(float *input, int n) {
   foo(input, n);
   asm("" : : : "d8","d9","d10","d11","d12","d13","d14","d15");
}

对应汇编输出

bar(float*, int):                              // @bar(float*, int)
        stp     d15, d14, [sp, #-64]!           // 16-byte Folded Spill
        stp     d13, d12, [sp, #16]             // 16-byte Folded Spill
        stp     d11, d10, [sp, #32]             // 16-byte Folded Spill
        stp     d9, d8, [sp, #48]               // 16-byte Folded Spill
        mov     x8, x0

现在的疑问是:有没有办法让非内联的foo函数知晓上层调用者已经处理了这些寄存器的溢出恢复,从而让foo不再自行执行d8-d15的保存与恢复操作?


内容的提问来源于stack exchange,提问作者Aki Suihkonen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:47:02