1.はじめに
前回の記事で書いたように、Z80用の独自言語であるpicle言語を今更ながら開発中で、それなりに動くようになってきました。前回の記事で書いたように将来的にはpicleコンパイラ自体をpicle言語で記述するセルフホスティングを実現したいと考えています。
そのために従来の「PIC24用のpicleコンパイラ」に追加した機能等について記録しておきたいと思います。
2.従来の言語仕様に追加した機能
セルフホスティングを実現する上で必要と思われる機能とコンパイラに追加した対処について以下に記載します。
2-1.必要な機能
picle言語ではfuncで関数宣言することでリターン値を返すことができますが、コンパイラを構築するためには2個の返却値が必要な場面がありました。C言語の場合であれば引数をポインタ渡しにして引数の値を変更して返したり、構造体のポインタをリターン値として返すことで実現できますが、現状のpicle言語ではこのような機能はありません。
2-2.対処
- ポインタ渡し対応
C言語のように変数のポインタを求める & 演算子に対応することで、関数への引数をポインタ渡しすることを可能にしました。また、引数のポインタの中身をアクセスする際にオフセット無しの配列(例 arg[0])の場合、オフセット演算をしないようにして高速化しました。
サンプル1(picle言語) :l 1:# pointer argment sample 2:# ver 0.01 2026/06/25 skyriver 3: 4:func hoge( a, b ) { 5: return = a[0] + b; 6: a[0] = a[0] + 1; 7:} 8: 9:proc main() { 10: var arg; 11: arg = 123; 12: PrnStr_( "return value : " ); 13: PrnDec_( hoge( &arg, 10 ) ); 14: PrnStr_( "\narg : " ); 15: PrnDec_( arg ); 16:} :run return value : 133 arg : 124 :
- リターン後の引数値の参照可
上記の対策は引数をアクセスする際にZ80ではどうしてもオーバーヘッドが生じてしまうので、関数コール時にコール側が事前にPUSHする引数を関数リターン後に破棄する際、第一引数と第二引数のPOPをそれぞれDE,BCレジスタで行うようにしました。
こうすることで関数内での引数の参照時のオーバーヘッドは生じず、関数コール元に戻った後に関数内での引数の最終値をasm()による埋め込みのマシン語を使うことで参照することが可能になります。
※追記 2026/07/13 高速化のため、引数が5個以上の場合はPOPせずにSPを加算処理するように変更
サンプル2(picle言語) :l 1:# pointer argment sample2 2:# ver 0.01 2026/06/25 skyriver 3: 4:func hoge( a, b ) { 5: return = a + b; 6: a = a + 1; 7:} 8: 9:proc main() { 10: var retval, arg; 11: arg = 123; 12: retval = hoge( arg, 10 ); 13: asm_($dd,$73,$fc,$dd,$72,$fb); # LD (IX-4),E; LD (IX-5),D 14: PrnStr_( "return value : " ); 15: PrnDec_( retval ); 16: PrnStr_( "\narg : " ); 17: PrnDec_( arg ); 18:} :run return value : 133 arg : 124 :
3.高速化の改善
今回、Z80用のpicle言語コンパイラを作成するにあたり、高速化した点をメモしておきます。現在開発中のコンパイラはメモリ上のソースをコンパイルし、即実行する運用を想定しているのでメモリ上にはコンパイラとコンパイルしたコードが共存します。このためコンパイラのサイズをなるべく小さくしたいので改善内容を精査し、下記の項目だけに留めています。- for ループのコンパイル
前回の記事にも書きましたが for 文のコンパイルではコードの生成順を入れ替えることでループ内のジャンプ命令が一つになるようにしています。
- オフセット無しの配列のアクセス
上記で記載したようにオフセット無しの配列(例 arg[0])のアクセス時はオフセット計算をしないようにしました。
- 変数のインクリメント/ディクリメント
for 文等で使用頻度の高い変数のインクリメント(例 i=i+1)とディクリメント(例 i=i-1)はマシン語の INC HL/DEC HL にコンパイルするようにしました。
4.コンパイル時間
開発中のZ80用独自言語のpicleはrun一発で実行できるインタプリタのようなコンパイラを目指しています。下の動画はX(旧Twitter)のメッセージに貼ったもので、固定小数点の乗算を使った asciiart(マンデルブロ)を表示するプログラムの実行状況です。runコマンド入力直後から表示が始まるまでの一瞬の待ち時間がコンパイルしている時間で、オンメモリでの1パスコンパイルなのでコンパイルは想定通りの速さです(この時の環境はZ80 12.5MHz)。
固定小数点乗算を使ったASCIIARTの実行画面を録画してみました
— skyriver (@wcinp) June 13, 2026
実行時間は6秒程度で、runコマンド後の若干の待ち時間がほぼコンパイル時間です
オンメモリでの1パスコンパイルなので想定どおりの速さですね pic.twitter.com/RgAHOAjIff
5.ベンチマーク
「AKI-80用モニターROM&Cコンパイラーセットの購入(その2)」の記事で書いたベンチマーク2を実行して比較してみました。動作環境はZ80がwait無しで20MHzで動作するCP/M環境です。今回のコンパイラはコンパイルがかなり高速ですがその反面、高速化対策はあまり注力していません。しかし、下表のベンチマーク結果表を見ると BDS C はもとより Z88DK よりも高速だったのは予想外な結果でした。
| 整数処理ベンチマーク2実行結果 |
|
|
| ※変更 2026/07/13 若干高速化(80.6s → 78.2s) |
picleでベンチマークプログラムを実行した画面のキャプチャも貼っておきます。
| picleでのベンチマーク2実行画面 |
|
|
6.おわりに
今回開発中の Z80 用の picle 言語コンパイラはコンパイル速度を速くするために1パスコンパイル方式にし、上述のようにコンパイル速度は想定通り速くできました。更にコンパイルしたコードに関しても上述のベンチマークで確認したように想定以上の結果になりました。今後は気が向いた時にセルフホスティング化していきたいと思います。
また、コンパイル結果をファイル化して独立した実行ファイルを生成できるようにしたり、ポケコン等で使われている特殊なCPUに対応する等、その気さえあれば色々な展開が可能だと思います。
[TOP] [ 前へ ] Z80用picle言語コンパイラの開発 [ 次へ ]


せっかく高速なコンパイラなので、コンパイル速度の比較も見たいです。
XCC-Vのサイズが他よりずいぶん小さいんですが、最終的に出力しない計算は省くような、特にベンチマークに効く最適化でもしているんでしょうか。
Z88DKのコンパイラはSDCC由来だと思っていたのですが、今では別物なんですね。
SDCCも新しい文法の規格に対応していても、あまり最適化はしていない認識でしたが、最近はこんなに最適化されているとは知りませんでした。
XCC-Vのサイズについては標準出力等がCP/MのBDOSコールを使った自作の簡易なものであることやスタートアップ処理(crt0)もCP/M用に作成した自作の簡易的なものであること等がサイズが小さい要因だと思います。
また、SDCCコンパイラ自体はZ88DKにも組み込まれていますが(ディフォルトでは別のコンパイラが使われる)、SDCCチームが頑張って高速化しているようなので速いですね。私が使ったことのあるZ80で使えるC言語のコンパイラの中でコンパイルされたコードの速度という観点ではLSIC-80がダントツで高速だと思います(でも今でも高額で個人での購入は辛いw)
LSIC-80や京都マイコンのPROASM/PARTNERとか、今でも売り続けるくらいには需要があるんでしょうね。30年以上の昔、秋葉原のぷらっとホームの店頭でため息をついた記憶が。
ANSI準拠前のLSIC-80をMSX-Cにライセンスしたバージョンを公式MSXエミュレータ上でしか使ったことがありませんが、たしかMSX-Cでは最適化オプションが無効でいまいちでした。
実機当時のMSX-Cは、リンクするライブラリのライセンス上、作ったバイナリの再配布もできなかったようですが、現行のMSXエミュレータ本に付属するMSX-Cでは、高速なエミュレータ上で開発できて再配布も可能のようです。できれば最終版LSIC-80相当にバージョンアップしてほしかった。