* 「10日くらいでできる!プログラミング言語自作入門」の続編#1-10b
-(by [[K]], 2021.05.13)

** (1) HL-20b
-HL-20aでレジスタ変数の扱いがまともになって、きっと実行速度も上がるだろうと思ったら、上がりませんでした。x86(32bit)のときは、同様の HL-14→HL-14a の改造で、ちゃんと速度が上がっていたので、この結果は少々不思議です。
|[[a21_txt02_4]]|HL-14|RIGHT:865行|RIGHT:21.5KB|レジスタ変数の導入(46行しか増えない簡単な改造だけど、結構な効果がある)|RIGHT:2.0倍|RIGHT:1.2倍|
|[[a21_txt02_4a]]|HL-14a|RIGHT:906行|RIGHT:22.5KB|レジスタ変数のための最適化(さらに41行を追加してすごい速さに!)|RIGHT:''1.0倍''|RIGHT:''0.9倍''|
||||||||
|[[a21_txt02_10]]|HL-20|RIGHT:964行|RIGHT:36.0KB|レジスタ変数の導入(65行しか増えない簡単な改造だけど、結構な効果がある)|RIGHT:2.1倍|RIGHT:1.0倍|
|[[a21_txt02_10a]]|HL-20a|RIGHT:1014行|RIGHT:37.0KB|レジスタ変数のための最適化(さらに50行を追加してすごい速さに!・・・なってない)|RIGHT:2.1倍|RIGHT:0.7倍|

-これはおそらく「コードアライン」ということをちゃんとやってこなかったせいなのではないかと私は考えました。ということでそれをここでやります。ちなみにx86(32bit)の時は、HL-15aでコードアラインに関する処理を入れていました。

-[1]defLabel()関数を以下のものと差し替え
 int align;
 
 void defLabel(int i)
 {
 +   if (align > 0) {
 +       int j = (icq - ic) & 15;	// 0-15.
 +       if (j > 0 && j <= 7) {
 +           putIcX64("66_0f_1f_84_00_00_00_00_00", 0, 0, 0, 0);
 +           j = (j + 9) & 15;
 +       }
 +       if (j > 0) {	// 8-15.
 +           static char *table[8] = {
 +               "0f_1f_84_00_00_00_00_00", "0f_1f_80_00_00_00_00",
 +               "66_0f_1f_44_00_00", "0f_1f_44_00_00", "0f_1f_40_00", "0f_1f_00", "66_90", "90"
 +           };
 +           putIcX64(table[j - 8], 0, 0, 0, 0);
 +       }
 +       align--;
 +   }
     var[i] = icq - ic;
 }
-[2]compile()関数に以下を追加
 +       } else if (phrCmp(39, "align();", pc)) {
 +           align = 1;
 +       } else if (phrCmp(40, "align(!!*0);", pc)) {
 +           align = var[tc[wpc[0]]];
----
-以上すべての改造を終えると、プログラムは1035行になります。

** (3) プログラムの説明
-これはx64に限らないのですが、多くのCPUでは分岐先のアドレスが切りのいい2進数かどうかによって、速度が出たりでなかったりします。
-ということで必要な時に最高速度が出せるように、必要に応じて余計なNOP命令を入れる、align命令を追加しました。
-align命令でアライン機能が有効な時は、defLabel()するときに、もし速度が出ないアドレスになっているときは(=16で割った時にあまりが出るアドレスになっているときは)、適当にNOP命令を入れて、「よいアドレス」まで進めてから、defLabel()するようにしています。
-x64のアライン用のNOP命令(ちなみにx86でも同じです)

|1バイトのNOP|90;|
|2バイトのNOP|66_90;|
|3バイトのNOP|0f_1f_00;|
|4バイトのNOP|0f_1f_40_00;|
|5バイトのNOP|0f_1f_44_00_00;|
|6バイトのNOP|66_0f_1f_44_00_00;|
|7バイトのNOP|0f_1f_80_00_00_00_00;|
|8バイトのNOP|0f_1f_84_00_00_00_00_00;|
|9バイトのNOP|66_0f_1f_84_00_00_00_00_00;|

-align()命令では、カッコ内に数値を書かなければ、次の1つのラベルだけがアライン有効になります。数値を書いた場合は、数値の回数だけアラインが有効になります。
-10億回ループのプログラムをrunする前に、align(100);とかを実行しておけば、HL-20bでも十分な速度で実行できるようになります。そしてそのあと、いつでもalign(0);などとすれば、多すぎたalign設定値をクリアすることができます。

** (4) 効果の確認

|[[a21_txt02_10]]|HL-20|RIGHT:964行|RIGHT:36.0KB|レジスタ変数の導入(65行しか増えない簡単な改造だけど、結構な効果がある)|RIGHT:2.1倍|RIGHT:1.0倍|
|[[a21_txt02_10a]]|HL-20a|RIGHT:1014行|RIGHT:37.0KB|レジスタ変数のための最適化(さらに50行を追加してすごい速さに!・・・なってない)|RIGHT:2.1倍|RIGHT:0.7倍|
|[[a21_txt02_10b]]|HL-20b|RIGHT:1035行|RIGHT:37.5KB|アライン命令を追加して、HL-20aの成果がはっきり見えるようになった|RIGHT:1.0倍|RIGHT:0.7倍|


** 次回に続く
-次回: ''a21_txt02_11''
-次回: [[a21_txt02_11]]

*こめんと欄
#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS