3.3 演算方法
3.3.7 ロードストア削除
■ポイント
メモリアクセス(ロード、ストア)命令を削減することで、実行サイクルを減少させます。
■説明
座標計算において、x,y,z値を毎回、メモリへロードストアすることは、性能を低下させる大 きな原因となります。できるだけ、座標値を構造体データ上で演算せずにFPUレジスタ変数上 で演算させ、メモリロードストアを減少させるようなプログラムにすることで、実行スピードの 向上を図ります。
■使用例
固定点PとP0,P1,P2から形成される面の各頂点距離(二乗値)をもとめ、距離を判定する。
改善前ソースコード
#define SCAL2(v) ((v)->x*(v)->x ¥ +(v)->y*(v)->y¥
+(v)->z*(v)->z)
#define SubVect(a,b)
((a)->x-=(b)->x,¥
(a)->y -= (b)->y,¥
(a)->z -= (b)->z) typedef struct {
float x,y,z;
} POINT3;
typedef struct { POINT3* v;
} POLI;
int f(POINT3 *p, POLI *poli, float rad) {
float dst2;
POINT3 dv;
dv=poli->v[0];
SubVect(&dv,p);
dst2=SCAL2(&dv);
if (dst2>rad) return 0;
dv=poli->v[1];
SubVect(&dv,p);
dst2=SCAL2(&dv);
if (dst2>rad) return 0;
dv=poli->v[2];
SubVect(&dv,p);
dst2=SCAL2(&dv);
if (dst2>rad) return 0;
改善後ソースコード
float scal2(POINT3 *p1, POINT3 *q1) {
float a,b,c;
float d,e,f;
float *p=(float *)p1,*q=(float
*)q1;
a=*p++; d=*q++;
b=*p++; e=*q++; a-=d;
c=*p++; f=*q++; b-=e;
c-=f;
return a*a+b*b+c*c;
}
int f(POINT3 *p,POLI *poli, float rad) {
float d;
POINT3 *q;
q=poli->v;
d2=scal2(q++,p);
if (d2>rad) return 0;
d2=scal2(q++,p);
if (d2>rad) return 0;
d2=scal2(q++,p);
if (d2>rad) return 0;
return 1;
}
改善前アセンブリ展開コード .EXPORT _f
.SECTION P,CODE,ALIGN=32 _f:
MOV.L R8,@-R15 MOV.L @R5,R3 ADD #-12,R15 MOV R15,R2 MOV.L @R3,R1 MOV.L R1,@R2 MOV.L @(4,R3),R1 MOV.L R1,@(4,R2) MOV.L @(8,R3),R1 MOV.L R1,@(8,R2) MOV R15,R0 NOP
FMOV.S @R0,FR2 MOV R15,R3 FMOV.S @R4,FR3 MOV R15,R2 FSUB FR3,FR2 FMOV.S FR2,@R0 MOV #4,R0 MOV R0,R1 ADD R4,R1
FMOV.S @(R0,R3),FR2 FMOV.S @R1,FR3 FSUB FR3,FR2 FMOV.S FR2,@(R0,R3) MOV #8,R0
MOV R0,R1 ADD R4,R1 MOV R15,R3 FMOV.S @(R0,R3),FR2 FMOV.S @R1,FR3 MOV R15,R1 FSUB FR3,FR2 FMOV.S FR2,@(R0,R3) MOV R15,R3 MOV R15,R0 NOP
MOV #4,R8 MOV R15,R7 ADD R7,R8 MOV R15,R6 MOV #4,R7 FMOV.S @R8,FR0 ADD R6,R7 FMOV.S @R1,FR2 FMOV.S @R7,FR3 FMUL FR0,FR3 FMOV.S @R0,FR0 MOV #8,R0 FMAC FR0,FR2,FR3 FMOV.S @(R0,R3),FR2 FMOV.S @(R0,R2),FR0 FMAC FR0,FR2,FR3 FMOV.S FR3,FR5 FCMP/GT FR4,FR5 BT L284 MOV.L @R5,R2 MOV R15,R3 ADD #12,R2
改善後アセンブリ展開コード .EXPORT _scal2 .EXPORT _f
.SECTION P,CODE,ALIGN=32 _scal2:
FMOV.S @R5+,FR5 FMOV.S @R4+,FR6 FMOV.S @R5+,FR7 FMOV.S @R4+,FR4 FSUB FR5,FR6 FMOV.S @R5,FR8 FSUB FR7,FR4 FMOV.S @R4,FR5 FMOV.S FR6,FR0 FSUB FR8,FR5 FMOV.S FR4,FR3 FMUL FR4,FR3 FMAC FR0,FR6,FR3 FMOV.S FR5,FR0 FMAC FR0,FR5,FR3 RTS
FMOV.S FR3,FR0 _f:
MOV.L R14,@-R15 MOV.L R13,@-R15 MOV R4,R13 FMOV.S FR15,@-R15 MOV.L @R5,R14 MOV R4,R5 STS.L PR,@-R15 MOV R14,R4 FMOV.S FR4,FR15 BSR _scal2 ADD #12,R14 FMOV.S FR0,FR4 FCMP/GT FR15,FR4 BT L297 MOV R14,R4 MOV R13,R5 BSR _scal2 ADD #12,R14 FMOV.S FR0,FR4 FCMP/GT FR15,FR4 BT L297 MOV R13,R5 BSR scal2 MOV R14,R4 FMOV.S FR0,FR4 FCMP/GT FR15,FR4 BF L295 L297:
BRA L293 MOV #0,R0 L295:
MOV #1,R0 L293:
LDS.L @R15+,PR FMOV.S @R15+,FR15 MOV.L @R15+,R13 RTS
MOV.L @R15+,R14 .END
MOV.L @R2,R1 MOV.L R1,@R3 MOV.L @(4,R2),R1 MOV.L R1,@(4,R3) MOV.L @(8,R2),R1 MOV.L R1,@(8,R3) MOV R15,R0 NOP
FMOV.S @R0,FR2 MOV R15,R3 FMOV.S @R4,FR3 MOV R15,R2 FSUB FR3,FR2 FMOV.S FR2,@R0 MOV #4,R0 MOV R0,R1 ADD R4,R1
FMOV.S @(R0,R3),FR2 FMOV.S @R1,FR3 FSUB FR3,FR2 FMOV.S FR2,@(R0,R3) MOV #8,R0
MOV R0,R1 ADD R4,R1 MOV R15,R3 FMOV.S @(R0,R3),FR2 FMOV.S @R1,FR3 MOV R15,R1 FSUB FR3,FR2 FMOV.S FR2,@(R0,R3) MOV R15,R3 MOV R15,R0 NOP
MOV #4,R8 MOV R15,R7 ADD R7,R8 MOV R15,R6 MOV #4,R7 FMOV.S @R8,FR0 ADD R6,R7 FMOV.S @R1,FR2 FMOV.S @R7,FR3 FMUL FR0,FR3 FMOV.S @R0,FR0 MOV #8,R0 FMAC FR0,FR2,FR3 FMOV.S @(R0,R3),FR2 FMOV.S @(R0,R2),FR0 FMAC FR0,FR2,FR3 FMOV.S FR3,FR5 FCMP/GT FR4,FR5 BT L284 MOV.L @R5,R2 MOV R15,R3 ADD #24,R2
FMOV.S @R0,FR2 MOV R15,R3 FMOV.S @R4,FR3 MOV R15,R2 FSUB FR3,FR2 FMOV.S FR2,@R0 MOV #4,R0 MOV R0,R1 ADD R4,R1
FMOV.S @(R0,R3),FR2 FMOV.S @R1,FR3 FSUB FR3,FR2 FMOV.S FR2,@(R0,R3) MOV #8,R0
MOV R0,R1 ADD R4,R1 MOV R15,R3 FMOV.S @(R0,R3),FR2 FMOV.S @R1,FR3 MOV R15,R1 FSUB FR3,FR2 FMOV.S FR2,@(R0,R3) MOV R15,R3 MOV R15,R0 NOP
MOV #4,R8 MOV R15,R7 ADD R7,R8 MOV R15,R6 MOV #4,R7 FMOV.S @R8,FR0 ADD R6,R7 FMOV.S @R1,FR2 FMOV.S @R7,FR3 FMUL FR0,FR3 FMOV.S @R0,FR0 MOV #8,R0 FMAC FR0,FR2,FR3 FMOV.S @(R0,R3),FR2 FMOV.S @(R0,R2),FR0 FMAC FR0,FR2,FR3 FMOV.S FR3,FR5 FCMP/GT FR4,FR5 BF L282 L284:
ADD #12,R15 MOV #0,R0 RTS
MOV.L @R15+,R8 L282:
MOV #1,R0 L280:
ADD #12,R15 RTS
MOV.L @R15+,R8 .END
■ 改善前後のコードサイズと実行速度
改善前 改善後
コードサイズ 350byte 104byte
実行速度 155cycle 75cycle
【注】測定条件は、SH-4、キャッシュミスは考慮していない。
■改善前後プログラム解説
両者のロードストアの回数を比較する。
x,y,zで1回とすると 改善前は
dv=poli->v[0]; LOAD 1回
SubVect(&dv,p); LOAD 2回 STORE 1回 dst2=SCAL2(&dv); LOAD 2回
if (dst2>rad) rerun 0;
これを3回繰り返すため、合計18回のLOAD/STOREである。
改善後は
a=*p++; d=*q++;
b=*p++; e=*q++; a-=d;
c=*p++; f=*q++; b-=e;
c-=f;
return a*a+b*b+c*c;
pとqのロードで計2回×3回=合計6回のLOAD/STOREとなります。
このようにメモリアクセスを1/3に減少することができます。SuperHマイコンの命令セット
には、基本的にメモリとの演算命令がないことから、FPUレジスタ上の演算に比べ命令数が多 くなります。
また、メモリへのストアはパイプラインの乱れを起こす原因にもなります。メモリアクセスを 減少させることは、パイプラインの流れをスムーズにさせることにもつながります。
■補足
改善後のプログラムでは、固定点Pを3回ロードしています。
これを、1回のロードですむように改善すれば、さらに効果があがります。
一般に固定点に対して、複数の面に対するループ処理を行うことを考えると、固定点は、構造
体でなく一度FPUレジスタ変数にロードしてから、演算を行うようなプログラムに変更してく
ださい。