64bit mode (AArch64) で走らせてみました。
命令もレジスタの構造も異なるのでコードは別物です。
検証が不完全で、この結果には間違いが含まれている可能性があります。
(1) (2) (3) (4) (5) iPhone5 HTL21 Nexus10 iPhone5s iPhone5s Swift Krait Cortex-A15 AArch32 AArch64 A6 APQ8064 Exynos5D A7 A7 1.3GHz 1.5GHz 1.7GHz 1.3GHz? 1.3GHz? -------------------------------------------------------------------- a:m44 vmla_A Q 1.293 1.337 0.619 0.700 ----- b:m44 vmla_B Q 1.359 0.931 0.569 0.670 ----- c:m44 vmla_A D 1.669 1.889 0.557 0.649 ----- d:m44 vmla_B D 1.329 1.532 0.568 0.745 ----- A:m44 vfma_A Q 1.632 1.882 0.746 0.707 0.692 (fmla v) B:m44 vfma_B Q 1.594 0.695 0.840 0.699 0.696 (fmla v) e:fadds A 3.090 2.774 2.383 3.551 1.043 (fadd s) f:fmuls A 3.167 2.747 2.369 3.475 1.548 (fmul s) g:fmacs A 6.180 5.574 2.956 3.480 ----- h:vfma.f32 A 6.180 2.747 2.957 3.480 3.185 (fmadd s) i:vadd.f32 D A 3.091 2.762 1.183 1.031 1.031 (fadd.2s) j:vmul.f32 D A 3.168 2.746 1.478 1.545 1.545 (fmul.2s) k:vmla.f32 D A 3.166 5.604 1.480 1.567 ----- o:vfma.f32 D A 3.167 2.833 1.479 1.574 1.753 (fmla.2s) l:vadd.f32 Q A 3.090 2.801 2.365 1.031 1.039 (fadd.4s) m:vmul.f32 Q A 3.166 2.761 2.364 1.548 1.548 (fmul.4s) n:vmla.f32 Q A 3.167 5.606 2.367 1.574 ----- *:vfma.f32 Q A ----- ----- ----- ----- 1.696 (fmla.4s) p:fadds B 6.181 3.467 2.956 6.953 3.663 (fadd s) q:fmuls B 6.180 3.556 3.558 6.652 3.296 (fmul s) r:fmacs B 2.361 6.298 5.912 9.867 ----- s:vfma.f32 B 2.363 3.430 5.910 9.859 3.292 (fmadd s) t:vadd.f32 D B 3.090 3.529 2.958 3.663 3.643 (fadd.2s) u:vmul.f32 D B 3.169 3.447 2.364 3.114 3.289 (fmul.2s) v:vmla.f32 D B 6.180 6.293 4.728 6.185 ----- z:vfma.f32 D B 6.181 3.437 4.730 6.188 6.237 (fmla.2s) w:vadd.f32 Q B 3.090 3.457 2.961 3.659 3.641 (fadd.4s) x:vmul.f32 Q B 3.167 3.428 2.363 3.101 3.276 (fmul.4s) y:vmla.f32 Q B 6.179 6.372 4.729 6.199 ----- *:vfma.f32 Q B ----- ----- ----- ----- 6.226 (fmla.4s) ↑数値は実行時間(秒) 数値が小さい方が高速
scalar 演算は予想通り AArch64 の方が高速に実行できるようです。
AArch64 では NEON に統合されていると考えられるため
vector 時と同等になっています。
ARMv8 の AArch64 では SIMD レジスタの構造が変わっており、
すべて 128bit サイズになっています。
スカラー演算はその一部だけが用いられる仕組みで、
ちょうど x86 の SSE と同じです。
スカラーのロードでもレジスタ全体がクリアされます。
32bit (ARMv7) では、Q(128bit) x 8 = D(64bit) x 16 = S(32bit) x 32
が同じ領域でした。
D は S の 2個分で、Q には S レジスタが 4個含まれています。
AArch32 の場合、スカラー演算はレジスタの部分書き換えに相当するので
パイプラインの実行効率が落ちているのではないかと考えられます。
fmadd が遅いのは Swift と傾向が似ています。
AArch64 はこの命令だけ 4 オペランドでした。
A: と B: は下記の通り。
; A: m44 fmla A Q ldp q0, q1, [%0] ldp q2, q3, [%0,#32] ldp q4, q5, [%1] ldp q6, q7, [%1,#32] fmul.4s v8, v0, v4[0] fmla.4s v8, v1, v4[1] fmla.4s v8, v2, v4[2] fmla.4s v8, v3, v4[3] str q8, [%2] 〜 fmul.4s v8, v0, v7[0] fmla.4s v8, v1, v7[1] fmla.4s v8, v2, v7[2] fmla.4s v8, v3, v7[3] str q8, [%2,#48]
; B: m44 fmla B Q ldp q0, q1, [%0] ldp q4, q5, [%1] ldp q6, q7, [%1,#32] fmul.4s v8, v0, v4[0] fmul.4s v9, v0, v5[0] fmul.4s v10, v0, v6[0] fmul.4s v11, v0, v7[0] ldp q2, q3, [%0,#32] 〜 fmla.4s v8, v3, v4[3] fmla.4s v9, v3, v5[3] fmla.4s v10, v3, v6[3] fmla.4s v11, v3, v7[3] stp q8, q9, [%2] stp q10, q11, [%2,#32]
レジスタ番号が一致しているので非常に書きやすくなりました。
関連ページ
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・2013/04/08:Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・2013/01/09:Qualcomm APQ8064 GPU Adreno 320 の速度
・2012/12/23:Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力