* Essen Rev2 (ess03h) -(by [[K]], 2017.08.23) ** これはなに? -[[EssenR2_ess03f]]の改良版です。 ** 主な差分 -大半の項目はすごいことではなく、むしろ今まできちんと作っていなかったことが問題だったというだけ。 -[1]グラフィックス描画ウィンドウを途中で閉じても例外が出なくなった(blaライブラリの改良)。 -[2] ! ~ - + などの単項演算子が機能するようになった。 -[3] & | ^ などの二項演算子が機能するようになった。 -[4] a = b < c みたいな演算が可能になった。 -[5] 最適化機能の強化。 -[6] $i00~$i03が利用可能になった。 ** 例1: シンプルな20億回ループ(1) -まずは、シンプルな20億回ループを書いてみる。なぜ20億回なのかというと、30億だと32ビットの符号付き整数に収まらなくなってしまうから。 i = 0 while (i < 2000000000) { i++ } -ess03hにはまだfor構文がないので、素直に20億回ループを書くとこうなる。 -これを prompt>ess03h sample1.txt na で処理させると、JITコンパイルで生成したx86のアセンブラコードが出てくる。 XOR $EAX $EAX MOV g032 $EAX label L000000001 MOV $EAX g032 INC $EAX $EAX MOV g032 $EAX CMP $EAX c##s20#77359400$ JL L000000001 -まあたいしたことないコードだ。当然たいして速くもない。 -これをCore_i7-2600/3.4GHz上で実行すると''3.85秒''くらいかかる。ちなみにソースコードをJITコンパイルして機械語に変換するまでに要した時間は0.001秒だった。 --JITコンパイル時間に関して言えば、50行程度のesmandelの場合は0.002秒である。 ** 例2: シンプルな20億回ループ(2) -ここで、変数iを整数専用レジスタに割り振ったらどうなるか。一行書くだけでよくて簡単なのでやってみよう。 i :== $i00 i = 0 while (i < 2000000000) { i++ } -これを同様にnaするとこうなる。 XOR $EBX $EBX label L000000001 INC $EBX $EBX CMP $EBX c##s20#77359400$ JL L000000001 -EBXレジスタに割り当てられているのが見て取れる。無駄なメモリアクセス命令もなくなった。 -これをCore_i7-2600/3.4GHzで実行すると、''0.567秒''で終わってしまう。大幅に改善していることが分かる。簡単に6.8倍も速くなってしまった。 ** 議論: EssenRev2の最適化の方針について -最近のEssenRev2では、最適化をがんばっている。新しい命令の追加とかはほとんどやっていない。それはこう考えたからだ。 --(1) JITコンパイル方式での実行速度はあまりにも魅力的である。今までは「Essenは速度を追求しない、速度がほしければインラインC言語で書けばよい」という見解だったが、C言語との速度比があまりにも大きいと「もうめんどくさいから最初から全部C言語で書く」ということを検討してしまう。それは望ましくない。またC言語は機種依存(CPU依存)があるので、それも好ましくない。 --(2) となれば、なにはともあれJITコンパイラ部分を整備してしまうほうがいい。このレイヤは将来も使いまわせる。今後私がどんな言語を作ることになったとしても、流用できる。 --(3) JITコンパイル方式を採用したのは、JITコンパイラのエンジンがそれほど大きくならずに済むと分かったことも後押しになっている。 -Essenはgccとは最適化の方針が明らかに異なっている。その理由を説明したい。 --(4) gccはプログラマに対して-Oオプションでレベルを指定させる以外の労力は極力かけまいとする。「何もしなくてもこんなに高速になりました!」を目指している。・・・それに対してEssenは高速にしたいときはそれなりの記述をするように要求する。ただしその記述は機種依存しない。高速な記述をしたときは、他の機種で不利になるようなことは原則としてない。むしろ他の機種でも高速になるだろう。 --(5) この方針の違いは意外に大きい。gccではとにかくコンパイラが頑張らなければいけないので、コンパイル時間は長くなるし、処理系は大きくなる。それでありとあらゆる手法を検討して、会心のコードを出力する。・・・Essenでは適用される最適化手法は限定されている上に、十分なヒントがソースコード上から得られるので、コンパイラは頑張らない。処理系も小さい。しかしそれでも、gcc比で0.8倍くらいの処理速度は容易に得られる。 --(6) たとえばgccはループがあってもその演算結果を使うことがないと判断した場合は、ループそのものを削除してしまう。でもそれは勇み足かもしれないではないか。もしかしたらwaitなどのためにループしていたのかもしれない。それで、gccではvolatile記述をすることでこれを抑制できる。・・・私はこれはおせっかいだと考える。プログラマが書いたループはもっと尊重されるべきだ。デフォルトが消さない動作であるべきだ。消してもいいループならそういうことを記述できるほうが良い。というか消してまでして高速化したいのならプログラマが自分で消せばいいではないか。プログラマが何も考えずに適当に書いて、それでもコンパイラが考え抜いて高速化するというのは、何かおかしい。バランスが悪い。人間がバカになる。 ** 説明: Essenの内部構造 -#0: 高次レイヤ(高級言語→仮想アセンブラ)(註:仮想アセンブラは機種依存がない) -#1: 仮想アセンブラ最適化レイヤ(仮想アセンブラ→仮想アセンブラ) -#2: ネイティブアセンブラ最適化レイヤ(仮想アセンブラ→ネイティブアセンブラ→ネイティブアセンブラ) -#3: 機械語出力レイヤ(つまりアセンブラ)(ネイティブアセンブラ→機械語) -#0と#1は機種依存しない。 -#1~#3は、他の言語に対しても流用できる。おそらくOSECPU-VMのバックエンドにも流用可能。 ** ダウンロード -http://khfdpl.osask.jp/download/ess03h.zip --ちなみにess03h.exeは31.5KB。 // :==の後ろにコメントを入れられなかった。 * こめんと欄 #comment