7. • 配列の和
• 素朴なasmコード
単純ループ
float sum(const float *x, size_t n) {
float r = 0;
for (size_t i = 0; i < n; i++) r += x[i];
return r;
}
xorps r, r // r = 0
test n, n
jz .exit
xor i, i // i = 0
.lp:
addss r, [x + i * 4] // r += x[i]
add i, 1 // i++
cmp i, n // if (i < n)
jne .lp // goto lp
.exit:
7 / 69
9. • iN x jN x kN個からなる3次元配列の(i, j, k)番目は
iN*jN*k+iN*j+i番目のアドレス
• アドレス計算にはコストがかかる
• addr = (jN * k + j) * iN + i
多次元配列の添え字の計算
iN
jN
kN
i
j
k
mov rdx, jN
imul rdx, k // jN * k
add rdx, j // jN * k + j
imul rdx, iN // (jN * k + j) * iN
add rdx, i // (jN * k + j) * iN + i
movss r, [x + rdx * 4]
9 / 69
10. • 多数のループの畳み込み
• ループの順序を入れ換えても計算結果は同じ
• キャッシュの影響で実行時間は異なる
• パラメータやCPUによって最適な順序が異なる
• 事前に多数のパターンを用意しておくのは組み合わせが大変
多重ループの順序
for oh
for ow
for oc
for ic
for kh
for kw
dst[oc, ow, oh] += ker[oc, ic, kw, kh] * src[ic, ow+kw, oh+kh]
10 / 69
46. • 符号の位置によって8パターンある
• fmad(a, b, c) ; a = a * b + c
• fmsb(a, b, c) ; a =-a * b + c
• fmla(a, b, c) ; a = a + b * c
• fmls(a, b, c) ; a = a - b * c
• 上記の符号反転
• fnmad(a, b, c); a =-a * b - c
• fnmsb(a, b, c); a = a * b - c
• fnmla(a, b, c); a =-a - b * c
• fnmls(a, b, c); a =-a + b * c
積和命令
46 / 69