2025年05月19日

AKI-80用モニターROM&Cコンパイラーセットの購入(その2)


1.はじめに
 前回の記事「AKI-80用モニターROM&Cコンパイラーセットの購入」の5ー2)整数処理での比較で秋月さんから購入したAKI-80用モニターROM&Cコンパイラーセットに入っているCコンパイラ(以降、XCC-Vと記す)が最も速い結果となりました。

整数処理ベンチマーク実行結果(再掲)

 これも再掲ですが、整数処理のベンチマークに使ったCソースは下記になります。

整数処理のベンチマーク用ソース(C言語)
/* * quiz solver * bench mark test */ #include <stdio.h> void Check( int a, int b, int c, int d, int e, int f ) { if ((b+b+f)!=e) return; if ((a+c+e)!=12) return; if ((b+d+f)!=9) return; if ((b+e+b)!=9) return; if ((a+b+d)!=12) return; if ((c+f+f)!=e) return; /* printf( "\nA B C D E F = %d %d %d %d %d %d",a,b,c,d,e,f ); */ } void search( void ) { int a,b,c,d,e,f; for (a=1; a<7; a++ ) { for ( b=1; b<7; b++ ) { for ( c=1; c<7; c++ ) { for ( d=1; d<7; d++ ) { for ( e=1; e<7; e++ ) { for ( f=1; f<7; f++ ) { Check(a,b,c,d,e,f); } } } } } } } void main( void ) { int i; for ( i = 0; i < 32; i++ ) { putchar( '.' ); search(); } /* printf( "\ncomplete!" ); */ }


2.実行時間の差異の主要な原因
 高速と言われる小規模デバイスに特化したSDCCよりもXCC-Vが速い原因を確認しようと思い、コンパイルした結果であるアセンブラソースを確認してみました。上記のように Check 関数は return 以外の実質的な実行処理が無いことからXCC-Vでは下記のように中身が省略された状態に最適化されていました。

XCC-VによるCheck関数のコンパイル結果
0029 _Check: 01FD DDE5 0030 push IX 01FF DD210000 0031 ld IX,0 0203 DD39 0032 add IX,SP 0033 %%DFP 6 0034 %%SYM a,14,type=5,cls=6,val=4,size=2 0035 %%SYM b,14,type=5,cls=6,val=6,size=2 0036 %%SYM c,14,type=5,cls=6,val=8,size=2 0037 %%SYM d,14,type=5,cls=6,val=10,size=2 0038 %%SYM e,14,type=5,cls=6,val=12,size=2 0039 %%SYM f,14,type=5,cls=6,val=14,size=2 0040 %%ENDD 0041 %%BF 0042 ; - if - 0043 ; RET 0044 %%LINE 000016 0045 %%EF 0205 DDF9 0046 ld SP,IX 0207 DDE1 0047 pop IX 0209 C9 0048 ret

 一方、SDCC 側のコンパイル結果は下記のようになっています。

SDCCによるCheck関数コンパイル結果
;--------------------------------- ; Function Check ;--------------------------------- _Check: push ix ld ix,0 add ix,sp ld l,(ix+6) ld h,(ix+7) add hl, hl ex de,hl ld l,(ix+14) ld h,(ix+15) add hl, de ld c,(ix+12) ld b,(ix+13) cp a, a sbc hl, bc jp NZ,l_Check_00113 ld a,(ix+4) add a,(ix+8) ld c, a ld a,(ix+5) adc a,(ix+9) ld b, a ld l,(ix+12) ld h,(ix+13) add hl, bc ld a, l sub a,0x0c or a, h jr NZ,l_Check_00113 ld a,(ix+6) add a,(ix+10) ld c, a ld a,(ix+7) adc a,(ix+11) ld b, a ld l,(ix+14) ld h,(ix+15) add hl, bc ld a, l sub a,0x09 or a, h jr NZ,l_Check_00113 ld a,(ix+6) add a,(ix+12) ld c, a ld a,(ix+7) adc a,(ix+13) ld b, a ld l,(ix+6) ld h,(ix+7) add hl, bc ld a, l sub a,0x09 or a, h jr NZ,l_Check_00113 ld a,(ix+4) add a,(ix+6) ld c, a ld a,(ix+5) adc a,(ix+7) ld b, a ld l,(ix+10) ld h,(ix+11) add hl, bc ld a, l sub a,0x0c or a, h jr NZ,l_Check_00113 ld a,(ix+8) add a,(ix+14) ld c, a ld a,(ix+9) adc a,(ix+15) ld b, a ld l,(ix+14) ld h,(ix+15) add hl, bc ld c,(ix+12) ld b,(ix+13) cp a, a sbc hl, bc jr Z,l_Check_00113 l_Check_00113: pop ix ret


3.ベンチマーク処理の変更
 実処理が無いことから中身を全て省略するというXCC-Vの最適化は大変素晴らしいのですが、ベンチマーク処理を実際の処理に近づけるために main() にあった'.'の表示をCheck()内に移動し、Check()内の処理が空の状態にならないように変更してみました(下記のリスト)。

整数処理のベンチマーク2のソース(C言語)
/* * quiz solver Ver0.02 2025/05/19 * bench mark test */ #include <stdio.h> void Check( int a, int b, int c, int d, int e, int f ) { if ((b+b+f)!=e) return; if ((a+c+e)!=12) return; if ((b+d+f)!=9) return; if ((b+e+b)!=9) return; if ((a+b+d)!=12) return; if ((c+f+f)!=e) return; putchar( '.' ); /* printf( "\nA B C D E F = %d %d %d %d %d %d",a,b,c,d,e,f ); */ } void search( void ) { int a,b,c,d,e,f; for (a=1; a<7; a++ ) { for ( b=1; b<7; b++ ) { for ( c=1; c<7; c++ ) { for ( d=1; d<7; d++ ) { for ( e=1; e<7; e++ ) { for ( f=1; f<7; f++ ) { Check(a,b,c,d,e,f); } } } } } } } void main( void ) { int i; for ( i = 0; i < 32; i++ ) { search(); } /* printf( "\ncomplete!" ); */ }

 XCC-VでのCheck関数のコンパイル結果が下記のリストのようになりました。変更後のベンチマーク2ではCheck関数の中身を省略できないのでIF文もソース通りコンパイルされています。

XCC-Vでの変更後のベンチマーク2のCheck関数のコンパイル結果
0028 %%FUNC Check,3,cls=2,type=0 0029 _Check: 01FD DDE5 0030 push IX 01FF DD210000 0031 ld IX,0 0203 DD39 0032 add IX,SP 0033 %%DFP 6 0034 %%SYM a,14,type=5,cls=6,val=4,size=2 0035 %%SYM b,14,type=5,cls=6,val=6,size=2 0036 %%SYM c,14,type=5,cls=6,val=8,size=2 0037 %%SYM d,14,type=5,cls=6,val=10,size=2 0038 %%SYM e,14,type=5,cls=6,val=12,size=2 0039 %%SYM f,14,type=5,cls=6,val=14,size=2 0040 %%ENDD 0041 %%BF 0042 ; - if - 0043 %%LINE 000009 0044 ;Expr(9): (b+ b+ f)!=e 0205 DD4E06 0045 ld C,(IX+6) 0208 DD4607 0046 ld B,(IX+7) 020B 60 0047 ld H,B 020C 69 0048 ld L,C 020D 09 0049 add HL,BC 020E DD4E0E 0050 ld C,(IX+14) 0211 DD460F 0051 ld B,(IX+15) 0214 09 0052 add HL,BC 0215 DD5E0C 0053 ld E,(IX+12) 0218 DD560D 0054 ld D,(IX+13) 021B B7 0055 or A 021C ED52 0056 sbc HL,DE 021E C2B602 R 0057 jr.x nz,L27 0058 ; - endif - - if - 0059 %%LINE 000010 0060 ;Expr(10): (a+ c+ e)!=12 0221 DD4E08 0061 ld C,(IX+8) 0224 DD4609 0062 ld B,(IX+9) 0227 DD6E04 0063 ld L,(IX+4) 022A DD6605 0064 ld H,(IX+5) 022D 09 0065 add HL,BC 022E 42 0066 ld B,D 022F 4B 0067 ld C,E 0230 09 0068 add HL,BC 0231 54 0069 ld D,H 0232 5D 0070 ld E,L 0233 210C00 0071 ld HL,12 0236 B7 0072 or A 0237 ED52 0073 sbc HL,DE 0239 207B 0074 jr.x nz,L27 0075 ; - endif - - if - 0076 %%LINE 000011 0077 ;Expr(11): (b+ d+ f)!=9 023B DD4E0A 0078 ld C,(IX+10) 023E DD460B 0079 ld B,(IX+11) 0241 DD6E06 0080 ld L,(IX+6) 0244 DD6607 0081 ld H,(IX+7) 0247 09 0082 add HL,BC 0248 DD4E0E 0083 ld C,(IX+14) 024B DD460F 0084 ld B,(IX+15) 024E 09 0085 add HL,BC 024F 44 0086 ld B,H 0250 4D 0087 ld C,L 0251 210900 0088 ld HL,9 0254 B7 0089 or A 0255 ED42 0090 sbc HL,BC 0257 205D 0091 jr.x nz,L27 0092 ; - endif - - if - 0093 %%LINE 000012 0094 ;Expr(12): (b+ e+ b)!=9 0259 DD4E0C 0095 ld C,(IX+12) 025C DD460D 0096 ld B,(IX+13) 025F DD6E06 0097 ld L,(IX+6) 0262 DD6607 0098 ld H,(IX+7) 0265 09 0099 add HL,BC 0266 DD4E06 0100 ld C,(IX+6) 0269 DD4607 0101 ld B,(IX+7) 026C 09 0102 add HL,BC 026D 44 0103 ld B,H 026E 4D 0104 ld C,L 026F 210900 0105 ld HL,9 0272 B7 0106 or A 0273 ED42 0107 sbc HL,BC 0275 203F 0108 jr.x nz,L27 0109 ; - endif - - if - 0110 %%LINE 000013 0111 ;Expr(13): (a+ b+ d)!=12 0277 DD4E06 0112 ld C,(IX+6) 027A DD4607 0113 ld B,(IX+7) 027D DD6E04 0114 ld L,(IX+4) 0280 DD6605 0115 ld H,(IX+5) 0283 09 0116 add HL,BC 0284 DD4E0A 0117 ld C,(IX+10) 0287 DD460B 0118 ld B,(IX+11) 028A 09 0119 add HL,BC 028B 44 0120 ld B,H 028C 4D 0121 ld C,L 028D 210C00 0122 ld HL,12 0290 B7 0123 or A 0291 ED42 0124 sbc HL,BC 0293 2021 0125 jr.x nz,L27 0126 ; - endif - - if - 0127 %%LINE 000014 0128 ;Expr(14): (c+ f+ f)!=e 0295 DD4E0E 0129 ld C,(IX+14) 0298 DD460F 0130 ld B,(IX+15) 029B DD6E08 0131 ld L,(IX+8) 029E DD6609 0132 ld H,(IX+9) 02A1 09 0133 add HL,BC 02A2 09 0134 add HL,BC 02A3 DD4E0C 0135 ld C,(IX+12) 02A6 DD460D 0136 ld B,(IX+13) 02A9 B7 0137 or A 02AA ED42 0138 sbc HL,BC 02AC 2008 0139 jr.x nz,L27 0140 ; - endif - 0141 %%LINE 000015 0142 ;Expr(15): putchar('.') 02AE 212E00 0143 ld HL,46 02B1 E5 0144 push HL 02B2 CD9001 E 0145 call _putchar 02B5 C1 0146 pop BC 0147 L27: 0148 ; RET 0149 %%LINE 000017 0150 %%EF 02B6 DDF9 0151 ld SP,IX 02B8 DDE1 0152 pop IX 02BA C9 0153 ret


4.変更後のベンチマーク2での測定結果
 変更後のベンチマーク2での処理時間の測定結果を下表にまとめました。
 測定対象のコンパイラの中でSDCCが最速という結果になりました。

変更後の整数処理ベンチマーク2実行結果

 コンパイル結果の違いについてCheck関数の最初のIF文の部分を抜粋したものを下図に示します。

Check関数の最初のIF文のコンパイル結果

 SDCCとXCC-Vを比較し、それぞれの良い点を列挙すると

【SDCCの良い点】
  • 2倍する際に ADD HL,HL を使い、変数アクセス回数を削減している
【XCC-Vの良い点】
  • 数式計算時に EX DE,HL を使用していない
と言えると思います。SDCC側でCarryをクリアするために OR A ではなく、 CP A を使っているのも面白いですね。

 最後にベンチマーク2の実行時間を測定した画面のキャプチャを貼っておきます。

変更後の整数処理ベンチマーク2の実行画面


[TOP] [ 前へ ] AKI-80用モニターROM&Cコンパイラーセットの購入 [ 次へ ]
posted by skyriver at 20:48| Comment(0) | Z80 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
コチラをクリックしてください