如何用ARM NEON内在函数实现ARMv7与AArch64兼容的向量全零检查?
问题:ARM NEON内在函数兼容ARMv7与AArch64实现全零向量检查
我正在使用ARM官方发布的ARM NEON内在函数开发,希望代码同时兼容ARMv7和AArch64架构。我原本采用如下汇编代码检查向量是否全零:
shrn v0.8b, v0.8h, #4 // 把v0中的字节压缩为半字节 fcmp d0, #0.0
当v0的所有字节为0x00或0xff时(我的代码场景符合该条件),这段汇编可正常工作。
我尝试将其转为如下C代码,该代码可在AArch64上成功编译并生成预期机器码:
static int veq_zero(uint8x16_t v) { uint8x8_t narrowed; /* 把每个字节压缩为半字节 */ narrowed = vshrn_n_u16(vreinterpretq_u16_u8(v), 4); /* 检查该向量是否全零 */ return (vdupd_lane_f64(vreinterpret_f64_u16(narrowed), 0) == 0.0); }
但ARMv7中不存在vdupd_lane_f64和vreinterpret_f64_u16调用,甚至整个float64x1_t类型及其相关函数都缺失。
请问如何将该程序逻辑转为兼容ARMv7 NEON与AArch64的C内在函数实现?
兼容实现方案
核心思路是保留原有的压缩逻辑(这部分在ARMv7和AArch64中通用),将向量全零检查改为使用64位整数操作,避开ARMv7不支持的float64x1_t相关接口:
#include <arm_neon.h> #include <stdint.h> static int veq_zero(uint8x16_t v) { // 与原汇编逻辑一致:将16字节向量拆为8个16位元素,每个右移4位后窄化为8字节 uint8x8_t narrowed = vshrn_n_u16(vreinterpretq_u16_u8(v), 4); // 将8字节向量重新解释为64位单元素向量,取出后转为标准uint64_t类型 uint64_t vec_val = vget_lane_u64(vreinterpret_u64_u8(narrowed), 0); // 判断是否全零,对应原汇编的fcmp d0, #0.0 return (vec_val == 0); }
说明
- 压缩逻辑复用:
vreinterpretq_u16_u8和vshrn_n_u16是ARMv7和AArch64 NEON都支持的内在函数,完全复现原汇编的字节压缩行为。 - 跨架构全零检查:
vreinterpret_u64_u8将uint8x8_t向量重新解释为uint64x1_t(64位单元素向量),该接口在两种架构下均存在。vget_lane_u64取出64位向量的唯一元素,得到标准C语言的uint64_t类型,直接与0比较即可判断压缩后的向量是否全零。
- 适配场景需求:如果你的实际需求是检测原向量全0x00或全0xff(即压缩后的向量全0x00或全0xff),可将返回条件修改为:
return (vec_val == 0 || vec_val == UINT64_C(0xffffffffffffffff));
内容的提问来源于stack exchange,提问作者fuz
相关产品推荐
相关产品推荐

