a25_kharcs2
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* kharcs #2
-(by [[K]], 2025.06.09)
** (0) これはなに?
-(kharcsページは、kharc開発でわかったことを整理して説明...
-今回説明したいこと: ~この順番でCコンパイラを作ったら早...
--[1]関数定義、インラインアセンブラ(2日目)
--[2]変数宣言、インラインアセンブラ内でのラベル宣言(3日...
--[3]四則演算、return、関数呼び出し(4日目)
--[4]普通のラベル宣言、条件分岐(5日目)
--[5]for構文、while構文、do~while構文(6日目)
--[6]ブロックif構文、アセンブラ、エミュレータ、JITコンパ...
** (1) 関数定義、インラインアセンブラ(2日目:6/5)
-とりあえず、以下の記述くらいならできるようになりました。
int func(int i)
{
asm { LodRMd(R0,SP,$i); AddRI(R0,3); } // R0=i+3;
}
-受け取った引数に3を足すだけのヘボ関数です。コンパイルす...
LbI(1); // func()
SubAI(SP,8);
StoAMd(RP,SP,0); // RP値を保存している(とりあえず今は...
LodRMd(R0,SP,8); AddRI(R0,3); // (ここはasmの中身)$i...
LodAMd(RP,SP,0); // RP値を復元している.
AddAI(SP,8);
Ret();
-引数に名前を付けて参照できるので、どこに何があるのかを人...
** (2) 変数宣言、インラインアセンブラ内でのラベル宣言(3...
-ローカル変数の宣言を可能にして、スタック内がどうなってい...
void main()
{
params(1); // このmain内で行われる関数呼び出しは、引...
asm {
MovRI(R0,46); StoRMd(R0,SP,0); CalII($fib,@lb0:)...
return R0;
}
}
int fib(int i)
{
int tmp;
params(1);
asm {
LodRMd(R0,SP,$i); CmpJleRII(R0,1,@skip); // if (...
SubRI(R0,2); StoRMd(R0,SP,0); ...
LodRMd(R0,SP,$i); SubRI(R0,1); StoRMd(R0,SP,0); ...
LodRMd(R1,SP,$tmp); AddRR(R0,R1); // R0 += tmp;
LbI(@skip:);
}
}
-このfib()部分のコンパイル結果はこうなります。
LbI(4); // fib()
SubAI(SP,16);
StoAMd(RP,SP,12);
LodRMd(R0,SP,16); CmpJleRII(R0,1,7); // if (i <= 1) got...
SubRI(R0,2); StoRMd(R0,SP,0); CalII(4...
LodRMd(R0,SP,16); SubRI(R0,1); StoRMd(R0,SP,0); CalII(4...
LodRMd(R1,SP,8); AddRR(R0,R1); // R0 += tmp;
LbI(7); // skip:
LodAMd(RP,SP,12);
AddAI(SP,16);
Ret();
-変数オフセットやラベルなどがすべて無事に数値化できていま...
-スタックはこんな感じになっています。
{ [SP+0:引数用の領域8バイト] [SP+8:変数tmp] [SP+12:RP保...
** (3) 四則演算、return、関数呼び出し(4日目:6/9)
-式の評価をできるようにしました。四則演算と、代入と、関数...
void main()
{
fib(46); asm { return R0; }
}
int fib(int i)
{
asm { LodRMd(R0,SP,$i); CmpJleRII(R0,1,@skip); }
i = fib(i - 2) + fib(i - 1); // ← ここがかっこいい!
asm { LbI(@skip:); }
return i;
}
-インラインアセンブラじゃないところは、すごくC言語っぽい...
-上記をコンパイルするとこうなります。fib()の部分を見てみ...
LbI(4); // fib()
SubAI(SP,24);
StoAMd(RP,SP,20);
LodRMd(R0,SP,24); CmpJleRII(R0,1,7); // (ここはasmの中...
LodRMd(R0,SP,24); // ムダ
SubRI(R0,2);
StoRMd(R0,SP,8); // ムダ
LodRMd(R0,SP,8); // ムダ
FreI(8);
StoRMd(R0,SP,0);
CalII(4,5);
StoRMd(R0,SP,8);
LodRMd(R0,SP,24);
SubRI(R0,1);
StoRMd(R0,SP,12); // ムダ
LodRMd(R0,SP,12); // ムダ
FreI(12);
StoRMd(R0,SP,0);
CalII(4,6);
StoRMd(R0,SP,12);
LodRMd(R0,SP,8);
LodRMd(R1,SP,12);
AddRR(R0,R1);
StoRMd(R0,SP,16);
FreI(8);
FreI(12);
LodRMd(R0,SP,16);
StoRMd(R0,SP,24);
FreI(16);
LbI(7); LodRMd(R0,SP,24); // (ここはasmの中身)
JmpI(8); // ムダ
LbI(8); // fib().ret:
LodAMd(RP,SP,20);
AddAI(SP,24);
Ret();
// { [SP+0:引数用の領域8バイト] [SP+8:内部生成した一時変...
-FreI()命令は、何もしないコメント命令ですので、ひとまず無...
-明らかなムダ命令が6命令も入っていますが、それを除けば、...
-ムダ命令は将来的に簡単なオプティマイザ(最適化処理)を入...
----
-最適化と言えば、定数式のコンパイル時の評価とかもやってい...
int func()
{
int i, j, k;
i = j = k = 1 + 2 * 3;
i = (j = 4) + 5;
}
-これをコンパイルするとこうなります。
LbI(1); // func()
SubAI(SP,16);
StoAMd(RP,SP,12);
MovRI(R0,7); // 1+2*3 をコンパイル時に計算して 7 にして...
StoRMd(R0,SP,8); // k
MovRI(R0,7);
StoRMd(R0,SP,4); // j
MovRI(R0,7);
StoRMd(R0,SP,0); // i
MovRI(R0,4);
StoRMd(R0,SP,4); // j
MovRI(R0,9); // 4+5 をコンパイル時に計算して 9 にしてい...
StoRMd(R0,SP,0); // i
LbI(2); // func().ret:
LodAMd(RP,SP,12);
AddAI(SP,16);
Ret();
-これはなかなかかしこいです。1日で作ったにしてはよくでき...
** (4) 普通のラベル宣言、条件分岐(5日目:6/10)
-次は普通のラベル定義と比較演算子とif文を作って、インライ...
void main()
{
fib(46); asm { return R0; }
}
int fib(int i)
{
if (i <= 1) goto skip;
i = fib(i - 2) + fib(i - 1);
skip:
return i;
}
-ついにfib()内からはインラインアセンブラを追放できました...
-gotoがちょっとかっこ悪いので、次はブロックのifを作りたい...
** (5) for構文、while構文、do~while構文(6日目:6/11)
-昨日の予定ではifのブロック構文を作る予定でしたが、 else ...
-これでブロック処理に慣れたので、次はすぐにifのブロック構...
int main()
{
int i;
for (i = 0x20; i <= 0x7e; i++) {
putchar(i);
}
putchar(0x0a);
asm { return 0; }
}
void putchar(int c)
{
asm { LodRMd(R0,SP,$c); putchar(R0); }
}
-++演算子もつけて、もうすっかりC言語っぽいです!(いやも...
** (6) ブロックif構文、アセンブラ、エミュレータ、JITコン...
-ブロックif構文はすぐにできました。
int main()
{
int i;
for (i = 1; i <= 100; i++) {
if (i % 15 == 0) {
asm { printf("FizzBuzz\n"); }
} else if (i % 3 == 0) {
asm { printf("Fizz\n"); }
} else if (i % 5 == 0) {
asm { printf("Buzz\n"); }
} else {
asm { LodRMd(R0,SP,$i); printf("%d\n", R0); }
}
}
asm { End(); }
}
-ちょっとインラインアセンブラが多すぎる気はしますが、とに...
-構文的には「インラインアセンブラ」ではありますが、実質的...
----
-さて、これだけで終わったら簡単すぎてつまらないので、もっ...
-目下の関心事としてはたくさん生成されているムダ命令の除去...
-それで思いついたのは、kharcのエミュレータを作るのはどの...
-kharcは[[a25_kharcs1]]の(2)にある通り、20個くらいしか命...
-「すごく大変そうだったら、途中でやめればいいやー。とりあ...
-まずアセンブラのソースコードのままでは実行しにくいので、...
struct KharcBinInst { unsigned char op, prm[3]; int imm;...
-こんな感じの8バイトの構造体を考えて、これがkharcの1命令...
-CmpJneRII()みたいに、一部immフィールドを2つもつ命令があ...
-この仕様でアセンブラを作ったところ、85行でできてしまいま...
-この仕様は大正解だなって思いました!(自画自賛)。
----
-それで次はエミュレータです。switch~caseで、opの値を見て...
-そしてこんなものでもちゃんと動いてしまったのです。・・・...
-上記FizzBuzzが、kccだけで実行できて結果が出ちゃうわけで...
-これで調子に乗ってfib(46)を計算すると・・・うーん、はい...
-まあ当然ですよね、エミュレータなんだから。・・・-でもな...
-こうなったら、JITコンパイラもやってみるしかないですよね...
----
-基本方針として、RxやAxを次のように実レジスタに割り当てま...
|R0|R1|R2||SP|RP|
|EAX|ECX|EDX||EBP|EBX|
-あとは機械語を調べながら作りました。・・・ https://c9x.m...
-結局、60行で書けました。・・・はい、ちょっと自分でも何を...
-半信半疑というか、もうほとんど信じられなくて疑いしかない...
----
-さすがに疲れたので、fib(46)でベンチマークを取って今日は...
|1.kccに内蔵させた自作のエミュレータで実行|RIGHT:191.798[...
|2.kccに内蔵させた自作のエミュレータで実行(改良版)|RIGH...
|3.kccに内蔵させた自作のJITコンパイラで実行|RIGHT:15.246[...
|4.kccが出力したアセンブラをgccでコンパイルして実行|RIGHT...
|5.fibのプログラムをそのままgccでコンパイルして実行|RIGHT...
-やっぱりgccは速いなあ(5)。・・・ムダ命令を削ったら、こ...
-じゃあ、4のコードからムダ命令を手動で削って、どのくらい...
-今回は速度を追及するための開発ではなくて、1のエミュレー...
** [[a25_kharcs3]]へつづく
終了行:
* kharcs #2
-(by [[K]], 2025.06.09)
** (0) これはなに?
-(kharcsページは、kharc開発でわかったことを整理して説明...
-今回説明したいこと: ~この順番でCコンパイラを作ったら早...
--[1]関数定義、インラインアセンブラ(2日目)
--[2]変数宣言、インラインアセンブラ内でのラベル宣言(3日...
--[3]四則演算、return、関数呼び出し(4日目)
--[4]普通のラベル宣言、条件分岐(5日目)
--[5]for構文、while構文、do~while構文(6日目)
--[6]ブロックif構文、アセンブラ、エミュレータ、JITコンパ...
** (1) 関数定義、インラインアセンブラ(2日目:6/5)
-とりあえず、以下の記述くらいならできるようになりました。
int func(int i)
{
asm { LodRMd(R0,SP,$i); AddRI(R0,3); } // R0=i+3;
}
-受け取った引数に3を足すだけのヘボ関数です。コンパイルす...
LbI(1); // func()
SubAI(SP,8);
StoAMd(RP,SP,0); // RP値を保存している(とりあえず今は...
LodRMd(R0,SP,8); AddRI(R0,3); // (ここはasmの中身)$i...
LodAMd(RP,SP,0); // RP値を復元している.
AddAI(SP,8);
Ret();
-引数に名前を付けて参照できるので、どこに何があるのかを人...
** (2) 変数宣言、インラインアセンブラ内でのラベル宣言(3...
-ローカル変数の宣言を可能にして、スタック内がどうなってい...
void main()
{
params(1); // このmain内で行われる関数呼び出しは、引...
asm {
MovRI(R0,46); StoRMd(R0,SP,0); CalII($fib,@lb0:)...
return R0;
}
}
int fib(int i)
{
int tmp;
params(1);
asm {
LodRMd(R0,SP,$i); CmpJleRII(R0,1,@skip); // if (...
SubRI(R0,2); StoRMd(R0,SP,0); ...
LodRMd(R0,SP,$i); SubRI(R0,1); StoRMd(R0,SP,0); ...
LodRMd(R1,SP,$tmp); AddRR(R0,R1); // R0 += tmp;
LbI(@skip:);
}
}
-このfib()部分のコンパイル結果はこうなります。
LbI(4); // fib()
SubAI(SP,16);
StoAMd(RP,SP,12);
LodRMd(R0,SP,16); CmpJleRII(R0,1,7); // if (i <= 1) got...
SubRI(R0,2); StoRMd(R0,SP,0); CalII(4...
LodRMd(R0,SP,16); SubRI(R0,1); StoRMd(R0,SP,0); CalII(4...
LodRMd(R1,SP,8); AddRR(R0,R1); // R0 += tmp;
LbI(7); // skip:
LodAMd(RP,SP,12);
AddAI(SP,16);
Ret();
-変数オフセットやラベルなどがすべて無事に数値化できていま...
-スタックはこんな感じになっています。
{ [SP+0:引数用の領域8バイト] [SP+8:変数tmp] [SP+12:RP保...
** (3) 四則演算、return、関数呼び出し(4日目:6/9)
-式の評価をできるようにしました。四則演算と、代入と、関数...
void main()
{
fib(46); asm { return R0; }
}
int fib(int i)
{
asm { LodRMd(R0,SP,$i); CmpJleRII(R0,1,@skip); }
i = fib(i - 2) + fib(i - 1); // ← ここがかっこいい!
asm { LbI(@skip:); }
return i;
}
-インラインアセンブラじゃないところは、すごくC言語っぽい...
-上記をコンパイルするとこうなります。fib()の部分を見てみ...
LbI(4); // fib()
SubAI(SP,24);
StoAMd(RP,SP,20);
LodRMd(R0,SP,24); CmpJleRII(R0,1,7); // (ここはasmの中...
LodRMd(R0,SP,24); // ムダ
SubRI(R0,2);
StoRMd(R0,SP,8); // ムダ
LodRMd(R0,SP,8); // ムダ
FreI(8);
StoRMd(R0,SP,0);
CalII(4,5);
StoRMd(R0,SP,8);
LodRMd(R0,SP,24);
SubRI(R0,1);
StoRMd(R0,SP,12); // ムダ
LodRMd(R0,SP,12); // ムダ
FreI(12);
StoRMd(R0,SP,0);
CalII(4,6);
StoRMd(R0,SP,12);
LodRMd(R0,SP,8);
LodRMd(R1,SP,12);
AddRR(R0,R1);
StoRMd(R0,SP,16);
FreI(8);
FreI(12);
LodRMd(R0,SP,16);
StoRMd(R0,SP,24);
FreI(16);
LbI(7); LodRMd(R0,SP,24); // (ここはasmの中身)
JmpI(8); // ムダ
LbI(8); // fib().ret:
LodAMd(RP,SP,20);
AddAI(SP,24);
Ret();
// { [SP+0:引数用の領域8バイト] [SP+8:内部生成した一時変...
-FreI()命令は、何もしないコメント命令ですので、ひとまず無...
-明らかなムダ命令が6命令も入っていますが、それを除けば、...
-ムダ命令は将来的に簡単なオプティマイザ(最適化処理)を入...
----
-最適化と言えば、定数式のコンパイル時の評価とかもやってい...
int func()
{
int i, j, k;
i = j = k = 1 + 2 * 3;
i = (j = 4) + 5;
}
-これをコンパイルするとこうなります。
LbI(1); // func()
SubAI(SP,16);
StoAMd(RP,SP,12);
MovRI(R0,7); // 1+2*3 をコンパイル時に計算して 7 にして...
StoRMd(R0,SP,8); // k
MovRI(R0,7);
StoRMd(R0,SP,4); // j
MovRI(R0,7);
StoRMd(R0,SP,0); // i
MovRI(R0,4);
StoRMd(R0,SP,4); // j
MovRI(R0,9); // 4+5 をコンパイル時に計算して 9 にしてい...
StoRMd(R0,SP,0); // i
LbI(2); // func().ret:
LodAMd(RP,SP,12);
AddAI(SP,16);
Ret();
-これはなかなかかしこいです。1日で作ったにしてはよくでき...
** (4) 普通のラベル宣言、条件分岐(5日目:6/10)
-次は普通のラベル定義と比較演算子とif文を作って、インライ...
void main()
{
fib(46); asm { return R0; }
}
int fib(int i)
{
if (i <= 1) goto skip;
i = fib(i - 2) + fib(i - 1);
skip:
return i;
}
-ついにfib()内からはインラインアセンブラを追放できました...
-gotoがちょっとかっこ悪いので、次はブロックのifを作りたい...
** (5) for構文、while構文、do~while構文(6日目:6/11)
-昨日の予定ではifのブロック構文を作る予定でしたが、 else ...
-これでブロック処理に慣れたので、次はすぐにifのブロック構...
int main()
{
int i;
for (i = 0x20; i <= 0x7e; i++) {
putchar(i);
}
putchar(0x0a);
asm { return 0; }
}
void putchar(int c)
{
asm { LodRMd(R0,SP,$c); putchar(R0); }
}
-++演算子もつけて、もうすっかりC言語っぽいです!(いやも...
** (6) ブロックif構文、アセンブラ、エミュレータ、JITコン...
-ブロックif構文はすぐにできました。
int main()
{
int i;
for (i = 1; i <= 100; i++) {
if (i % 15 == 0) {
asm { printf("FizzBuzz\n"); }
} else if (i % 3 == 0) {
asm { printf("Fizz\n"); }
} else if (i % 5 == 0) {
asm { printf("Buzz\n"); }
} else {
asm { LodRMd(R0,SP,$i); printf("%d\n", R0); }
}
}
asm { End(); }
}
-ちょっとインラインアセンブラが多すぎる気はしますが、とに...
-構文的には「インラインアセンブラ」ではありますが、実質的...
----
-さて、これだけで終わったら簡単すぎてつまらないので、もっ...
-目下の関心事としてはたくさん生成されているムダ命令の除去...
-それで思いついたのは、kharcのエミュレータを作るのはどの...
-kharcは[[a25_kharcs1]]の(2)にある通り、20個くらいしか命...
-「すごく大変そうだったら、途中でやめればいいやー。とりあ...
-まずアセンブラのソースコードのままでは実行しにくいので、...
struct KharcBinInst { unsigned char op, prm[3]; int imm;...
-こんな感じの8バイトの構造体を考えて、これがkharcの1命令...
-CmpJneRII()みたいに、一部immフィールドを2つもつ命令があ...
-この仕様でアセンブラを作ったところ、85行でできてしまいま...
-この仕様は大正解だなって思いました!(自画自賛)。
----
-それで次はエミュレータです。switch~caseで、opの値を見て...
-そしてこんなものでもちゃんと動いてしまったのです。・・・...
-上記FizzBuzzが、kccだけで実行できて結果が出ちゃうわけで...
-これで調子に乗ってfib(46)を計算すると・・・うーん、はい...
-まあ当然ですよね、エミュレータなんだから。・・・-でもな...
-こうなったら、JITコンパイラもやってみるしかないですよね...
----
-基本方針として、RxやAxを次のように実レジスタに割り当てま...
|R0|R1|R2||SP|RP|
|EAX|ECX|EDX||EBP|EBX|
-あとは機械語を調べながら作りました。・・・ https://c9x.m...
-結局、60行で書けました。・・・はい、ちょっと自分でも何を...
-半信半疑というか、もうほとんど信じられなくて疑いしかない...
----
-さすがに疲れたので、fib(46)でベンチマークを取って今日は...
|1.kccに内蔵させた自作のエミュレータで実行|RIGHT:191.798[...
|2.kccに内蔵させた自作のエミュレータで実行(改良版)|RIGH...
|3.kccに内蔵させた自作のJITコンパイラで実行|RIGHT:15.246[...
|4.kccが出力したアセンブラをgccでコンパイルして実行|RIGHT...
|5.fibのプログラムをそのままgccでコンパイルして実行|RIGHT...
-やっぱりgccは速いなあ(5)。・・・ムダ命令を削ったら、こ...
-じゃあ、4のコードからムダ命令を手動で削って、どのくらい...
-今回は速度を追及するための開発ではなくて、1のエミュレー...
** [[a25_kharcs3]]へつづく
ページ名: