ARM NEONの128bit演算とgcc (2)
比較演算
素直に比較すると要素ごとの比較になり、意図した結果にならない。
(そもそも結果はboolで欲しいのにベクトルになってしまう)
[code lang="C"]
#include <arm_neon.h>int main()
{
uint32x4_t mm0={1,2,3,4};
uint32x4_t mm1={1,2,4,8};
uint32x4_t mm2=(mm0==mm1);
uint32x4_t mm3=(mm0!=mm1);printf("eq? %08x,%08x,%08x,%08xn",mm2[0],mm2[1],mm2[2],mm2[3]);
printf("ne? %08x,%08x,%08x,%08xn",mm3[0],mm3[1],mm3[2],mm3[3]);return 0;
}
[/code]
$ g++-4.8 -W -Wall -D_GCC_ -std=gnu++11 -O3 -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -mvectorize-with-neon-quad -ffast-math -ftree-vectorizer-verbose=9 -o test2 test2.o $ ./test2 eq? ffffffff,ffffffff,00000000,00000000 ne? 00000000,00000000,ffffffff,ffffffff
得られた結果の and をとれば ==、or を取れば != が実現できるが、それなら最初から32bit単位で比較した方がマシ。
先人の記事
皆さん困っているようで、Stack Overflowにも記事があった。
- Fastest way to test a 128 bit NEON register for a value of 0 using intrinsics? – Stack Overflow
- vectorization – ARM NEON: comparing 128 bit values – Stack Overflow
上の記事は0との比較。2つの回答が寄せられている。
下記は短い方。VMRS命令は gccのARM NEON Intrinsicsには存在しないようなので、アセンブラで書かないといけない。
(cumulative saturation flag to be clearという指摘もある)
VTST.8 q1, q0, q0 VQADD.u8 q0, q1 VMRS r0,FPSCRFastest way to test a 128 bit NEON register for a value of 0 using intrinsics? – Stack Overflow
こちらは Intrinsics で書ける方。vtbl命令って高速なんでしょうか?
[code lang="C"]
inline bool is_zero(int32x4_t v) noexcept
{
v = v == int32x4{};return !int32x2_t(
vtbl2_s8(
int8x8x2_t{
int8x8_t(vget_low_s32(v)),
int8x8_t(vget_high_s32(v))
},
int8x8_t{0, 4, 8, 12}
)
)[0];
}
[/code]
Fastest way to test a 128 bit NEON register for a value of 0 using intrinsics? – Stack Overflow
32bit単位で処理
要素ごとの処理が意外に早い。vtblが遅いんだろうな。
| と || では、|| が良さそう。分岐がある方が早いのは意外。
[code lang="C"]
bool is_zero2(uint32x4_t v) noexcept
{
return (v[0]|v[1]|v[2]|v[3])==0;
}bool is_zero3(uint32x4_t v) noexcept
{
return !(v[0]||v[1]||v[2]||v[3]);
}
[/code]
任意の比較
単純に32bit単位要素比較するか、xorして0比較するか。
うちの環境では下記の3番目が良さそう。
[code lang="C"]
bool equal_simple(uint32x4_t v, uint32x4_t w) noexcept
{
return ((v[0]==w[0])&&(v[1]==w[1])&&(v[2]==w[2])&&(v[3]==w[3]));
}bool equal_xor(uint32x4_t v, uint32x4_t w) noexcept
{
uint32x4_t x = v^w;
return !(x[0]|x[1]|x[2]|x[3]);
}bool equal_xor2(uint32x4_t v, uint32x4_t w) noexcept
{
uint32x4_t x = v^w;
return !(x[0]||x[1]||x[2]||x[3]);
}
[/code]
ディスカッション
コメント一覧
まだ、コメントがありません