返回 ARM NEON 下的 Z 标志
returning Z flag under ARM NEON
我有一个 NEON 函数在做一些比较:
inline bool all_ones(int32x4_t v) noexcept
{
v = ~v;
::std::uint32_t r;
auto high(vget_high_s32(int32x4_t(v)));
auto low(vget_low_s32(int32x4_t(v)));
asm volatile ("VSLI.I32 %0, %1, #16" : "+w"(high), "+w"(low));
asm volatile ("VCMP.F64 %0, #0" : "=w"(high));
asm volatile ("VMRS %0, FPSCR" : "=r"(r) : "w"(high));
return r & (1 << 30);
}
v
的分量(4 个整数)只能是全 1 或全 0。如果所有 4 个组件都是 1,则函数 returns true
和 false
否则。 return 部分扩展为 3 条指令,这对我来说很多。有没有更好的方法来 return Z 标志?
编辑:经过长时间的苦思冥想,上面的内容可以替换为:
inline bool all_ones(int32x4_t const v) noexcept
{
return int32_t(-1) == int32x2_t(
vtbl2_s8(
int8x8x2_t{
int8x8_t(vget_low_s32(int32x4_t(v))),
int8x8_t(vget_high_s32(int32x4_t(v)))
},
int8x8_t{0, 4, 8, 12}
)
)[0];
}
NEON中存在掩码提取指令。
如果可以避免,你真的不想将 NEON 与 VFP 混合使用。
我建议:
bool all_ones(int32x4_t v) {
int32x2_t l = vget_low_s32(v), h = vget_high_s32(v);
uint32x2_t m = vpmin_u32(vreinterpret_u32_s32(l),
vreinterpret_u32_s32(h));
m = vpmin_u32(m, m);
return vget_lane_u32(m, 0) == 0xffffffff;
}
如果您确定唯一的非零值将是 0xffffffff
,那么您可以放弃比较。独立编译它可能有几个不必要的操作,但是当它内联时编译器应该修复它。
这似乎可以解决问题:
inline bool all_ones(int32x4_t v) noexcept
{
v = ~v;
auto high(vget_high_s32(int32x4_t(v)));
auto low(vget_low_s32(int32x4_t(v)));
asm volatile ("VSLI.I32 %0, %1, #16" : "+w"(high), "+w"(low));
return !reinterpret_cast<double&>(high);
}
但是 zip 和 pairwise add 技巧产生了更好的代码。
我有一个 NEON 函数在做一些比较:
inline bool all_ones(int32x4_t v) noexcept
{
v = ~v;
::std::uint32_t r;
auto high(vget_high_s32(int32x4_t(v)));
auto low(vget_low_s32(int32x4_t(v)));
asm volatile ("VSLI.I32 %0, %1, #16" : "+w"(high), "+w"(low));
asm volatile ("VCMP.F64 %0, #0" : "=w"(high));
asm volatile ("VMRS %0, FPSCR" : "=r"(r) : "w"(high));
return r & (1 << 30);
}
v
的分量(4 个整数)只能是全 1 或全 0。如果所有 4 个组件都是 1,则函数 returns true
和 false
否则。 return 部分扩展为 3 条指令,这对我来说很多。有没有更好的方法来 return Z 标志?
编辑:经过长时间的苦思冥想,上面的内容可以替换为:
inline bool all_ones(int32x4_t const v) noexcept
{
return int32_t(-1) == int32x2_t(
vtbl2_s8(
int8x8x2_t{
int8x8_t(vget_low_s32(int32x4_t(v))),
int8x8_t(vget_high_s32(int32x4_t(v)))
},
int8x8_t{0, 4, 8, 12}
)
)[0];
}
NEON中存在掩码提取指令。
如果可以避免,你真的不想将 NEON 与 VFP 混合使用。
我建议:
bool all_ones(int32x4_t v) {
int32x2_t l = vget_low_s32(v), h = vget_high_s32(v);
uint32x2_t m = vpmin_u32(vreinterpret_u32_s32(l),
vreinterpret_u32_s32(h));
m = vpmin_u32(m, m);
return vget_lane_u32(m, 0) == 0xffffffff;
}
如果您确定唯一的非零值将是 0xffffffff
,那么您可以放弃比较。独立编译它可能有几个不必要的操作,但是当它内联时编译器应该修复它。
这似乎可以解决问题:
inline bool all_ones(int32x4_t v) noexcept
{
v = ~v;
auto high(vget_high_s32(int32x4_t(v)));
auto low(vget_low_s32(int32x4_t(v)));
asm volatile ("VSLI.I32 %0, %1, #16" : "+w"(high), "+w"(low));
return !reinterpret_cast<double&>(high);
}
但是 zip 和 pairwise add 技巧产生了更好的代码。