「10日くらいでできる!プログラミング言語自作入門」の続編#1-10b

  • (by K, 2021.05.13)

(1) HL-20b

  • HL-20aでレジスタ変数の扱いがまともになって、きっと実行速度も上がるだろうと思ったら、上がりませんでした。x86(32bit)のときは、同様の HL-14→HL-14a の改造で、ちゃんと速度が上がっていたので、この結果は少々不思議です。
    a21_txt02_4HL-14865行21.5KBレジスタ変数の導入(46行しか増えない簡単な改造だけど、結構な効果がある)2.0倍1.2倍
    a21_txt02_4aHL-14a906行22.5KBレジスタ変数のための最適化(さらに41行を追加してすごい速さに!)1.0倍0.9倍
    a21_txt02_10HL-20964行36.0KBレジスタ変数の導入(65行しか増えない簡単な改造だけど、結構な効果がある)2.1倍1.0倍
    a21_txt02_10aHL-20a1014行37.0KBレジスタ変数のための最適化(さらに50行を追加してすごい速さに!・・・なってない)2.1倍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バイトのNOP90;
2バイトのNOP66_90;
3バイトのNOP0f_1f_00;
4バイトのNOP0f_1f_40_00;
5バイトのNOP0f_1f_44_00_00;
6バイトのNOP66_0f_1f_44_00_00;
7バイトのNOP0f_1f_80_00_00_00_00;
8バイトのNOP0f_1f_84_00_00_00_00_00;
9バイトのNOP66_0f_1f_84_00_00_00_00_00;
  • align()命令では、カッコ内に数値を書かなければ、次の1つのラベルだけがアライン有効になります。数値を書いた場合は、数値の回数だけアラインが有効になります。
  • 10億回ループのプログラムをrunする前に、align(100);とかを実行しておけば、HL-20bでも十分な速度で実行できるようになります。そしてそのあと、いつでもalign(0);などとすれば、多すぎたalign設定値をクリアすることができます。

(4) 効果の確認

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

次回に続く

こめんと欄


コメントお名前NameLink

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-05-13 (木) 15:20:52 (163d)