a25_kharcs7
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 「60分でできる!JITコンパイラ自作入門」
-(by [[K]], 2025.07.24)
** (0)
-JITコンパイラはインタプリタを高速にするために使われる定...
-たいして難しい技術ではないのですが、多くの人は難しいと漠...
-だから解説します。
-以下でも示しますが、普通のインタプリタをJITコンパイラに...
-JITコンパイラ化する以外で10倍も速くするのは相当に困難な...
-タイトルでは雑に60分とか書きましたが、ざっと理解するだけ...
** (1) 64bit-インタプリタ編 [61行]
-まず、以下のような命令セットを想定して、インタプリタとJI...
Sub_AI(SP,16); // SP = SP - 16;
Mov_RI(R0,0); // R0 = 0;
Sto_RMD(R0,SP,0); // [SP+0] = R0;
Sto_RMD(R0,SP,8); // [SP+8] = R0;
Lb_I(1); // L_1:
Lod_RMD(R0,SP,8); // R0 = [SP+8];
Lod_RMD(R1,SP,0); // R1 = [SP+0];
Add_RR(R0,R1); // R0 += R1;
Sto_RMD(R0,SP,0); // [SP+0] = R0;
Lod_RMD(R0,SP,8); // R0 = [SP+8];
Add_RI(R0,1); // R0 += 1;
Sto_RMD(R0,SP,8); // [SP+8] = R0;
CmpJlt_RII(R0,100000000,1); // if (R0 < 100000000) goto...
Lod_RMD(R0,SP,0); // R0 = [SP+0];
Add_AI(SP,16); // SP = SP + 16;
End(); // R0に計算結果が入っているので、それを表示して...
// ちなみに上記のコードは下記のソースコードをkccにコンパ...
// int s, i; s = 0;
// for (i = 0; i < 100000000; i++) { s = s + i; }
// つまり、0から99999999までの和を計算しています.
|Mov_RI(Rx,const);|整数レジスタ(Rx)に定数を代入|Rx = cons...
|Lod_RMD(Rx,Ax,disp);|メモリから値を読んで整数レジスタに...
|Sto_RMD(Rx,Ax,disp);|整数レジスタの値をメモリに書き込む|...
|Add_RR(Rx,Ry);|整数レジスタ同士の加算|Rx += Ry;|
|Add_RI(Rx,const);|整数レジスタに定数を加算|Rx += const;|
|Add_AI(Ax,const);|アドレスレジスタ(Ax)に定数を加算|Ax +=...
|Sub_AI(Ax,const);|アドレスレジスタに定数を減算|Ax -= con...
|Lb_I(x);|分岐先指定用のラベル定義命令(ラベルには名前は...
|CmpJlt_RII(Rx,const,y);|条件分岐命令|if (Rx < const) got...
|End();|R0の値を表示して終了||
-この10個の命令があれば上記は動きます。
-SPはA6レジスタの別名だということにします。
----
-ということでこんなプログラムを作りました。
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
struct Code { int64_t op, a, b, c; };
enum { Mov_RI=1, Lod_RMD, Sto_RMD, Add_RR, Add_RI, Add_A...
enum { R0=0, R1=1, SP=6 };
int main()
{
static struct Code t[17] = {
{ Sub_AI, SP, 16, -0 }, // -0は命令としては意味を持...
{ Mov_RI, R0, 0, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Sto_RMD, R0, SP, 8 },
{ Lb_I, 1, -0, -0 },
{ Lod_RMD, R0, SP, 8 },
{ Lod_RMD, R1, SP, 0 },
{ Add_RR, R0, R1, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Lod_RMD, R0, SP, 8 },
{ Add_RI, R0, 1, -0 },
{ Sto_RMD, R0, SP, 8 },
{ CmpJlt_RII, R0, 100000000, 1 },
{ Lod_RMD, R0, SP, 0 },
{ Add_AI, SP, 16, -0 },
{ End, -0, -0, -0 },
{ 0, -0, -0, -0 }
};
int64_t lb[256], r[8], a[8], pc;
char m[256]; // メモリ.
// Lb_I(x)命令を探して位置をlb[]に格納する.
for (pc = 0; t[pc].op > 0; pc++) {
if (t[pc].op == Lb_I) { lb[t[pc].a] = pc + 1; }
// 高速化のために、ラベル命令の次の命令の位置を登録...
}
// 実行開始.
pc = 0; a[6] = 256;
clock_t tm0 = clock();
for (;;) {
struct Code *tp = &t[pc]; int64_t *mp;
switch (tp->op) {
case Mov_RI: r[tp->a] = tp->b; pc++; continue;
case Lod_RMD: mp = (int64_t *) (m + a[tp->b] + tp->c...
case Sto_RMD: mp = (int64_t *) (m + a[tp->b] + tp->c...
case Add_RR: r[tp->a] += r[tp->b]; pc++; continue;
case Add_RI: r[tp->a] += tp->b; pc++; continue;
case Add_AI: a[tp->a] += tp->b; pc++; continue;
case Sub_AI: a[tp->a] -= tp->b; pc++; continue;
case Lb_I: pc++; continue;
case CmpJlt_RII: if (r[tp->a] < tp->b) { pc = lb[tp-...
case End: goto fin;
}
}
fin:
printf("R0=%" PRId64 " (%.3f[sec])\n", r[0], (clock() ...
return 0;
}
-実行すると R0=4999999950000000 と表示されます。
** (2) 64bit-JITコンパイラ編(x64用のコード生成) [69行]
-適当に作ればこんな感じです。
-Lod_RMD/Sto_RMD命令では、第二パラメータにSPしか指定しな...
-Sub_AI/Add_AI命令でも第一パラメータにSPしか指定しない想...
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
struct Code { int64_t op, a, b, c; };
enum { Mov_RI=1, Lod_RMD, Sto_RMD, Add_RR, Add_RI, Add_A...
enum { R0=0, R1=1, SP=6 };
#include <windows.h>
void *mallocRWX(int siz) { return VirtualAlloc(0, siz, M...
void set32(char *p, int64_t i) { p[0] = i & 0xff; p[1] =...
void set64(char *p, int64_t i) { set32(p, i); set32(p + ...
int main()
{
static struct Code t[17] = {
{ Sub_AI, SP, 16, -0 }, // -0は命令としては意味を持...
{ Mov_RI, R0, 0, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Sto_RMD, R0, SP, 8 },
{ Lb_I, 1, -0, -0 },
{ Lod_RMD, R0, SP, 8 },
{ Lod_RMD, R1, SP, 0 },
{ Add_RR, R0, R1, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Lod_RMD, R0, SP, 8 },
{ Add_RI, R0, 1, -0 },
{ Sto_RMD, R0, SP, 8 },
{ CmpJlt_RII, R0, 100000000, 1 },
{ Lod_RMD, R0, SP, 0 },
{ Add_AI, SP, 16, -0 },
{ End, -0, -0, -0 },
{ 0, -0, -0, -0 }
};
int64_t lb[256], r[8], pc, pass, rip;
char *tx = mallocRWX(65536); // とりあえず64KB.
// 方針: R0はRAX, R1はRCXに割り当てる. SPはRSPに割り当...
// JITコンパイル開始.
for (pass = 0; pass < 2; pass++) { // あえて2回まわす.
rip = 0;
for (pc = 0; t[pc].op > 0; pc++) {
struct Code *tp = &t[pc];
switch (tp->op) {
case Mov_RI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Lod_RMD: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Sto_RMD: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Add_RR: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Add_RI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Add_AI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Sub_AI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Lb_I: lb[tp->a] = rip; continue;
case CmpJlt_RII: tx[rip + 0] = 0x48; tx[rip + 1] =...
tx[rip + 13] = 0x0f; tx[rip + 14] = 0x8c; set32(...
case End: tx[rip + 0] = 0xc3; rip++; continue;
}
}
}
// int i; for (i = 0; i < rip; i++) printf("%02x ", ((...
// 実行開始.
int64_t (*f)() = (void *) tx;
clock_t tm0 = clock();
r[0] = f();
printf("R0=%" PRId64 " (%.3f[sec])\n", r[0], (clock() ...
return 0;
}
-当然ですが、実行すると R0=4999999950000000 と表示されま...
-変数passを使って、コード生成を2回やっています。これはほ...
-機械語を生成している部分は、まあ普通に見て意味不明だろう...
-そして10倍以上速いのです。
** (3) 今回使った機械語
48 bx [8バイト] : RAX/RCX/RDXに定数を代入. x=8:RAX, x=9:...
48 03 xx : レジスタをレジスタに加える演算( a += b; ). xx...
48 81 xx [4バイト] : レジスタと32bit整数定数の演算. 定数...
48 3b xx : レジスタ同士の比較.
0f 8c [4バイト] : 条件分岐(8cならJL)
c3 : return;
48 8b xx 24 [disp] : レジスタ=[RSP+disp]; xx=84+a*8.
48 89 xx 24 [disp] : [RSP+disp]=レジスタ; xx=84+a*8.
-参考にしたサイト(もし基礎的なことから勉強したいなら、以...
--REXプリフィックス https://www.wdic.org/w/SCI/REX%E3%83%...
--SIBバイト https://www.wdic.org/w/SCI/SIB%E3%83%90%E3%82...
--https://c9x.me/x86/
--http://ref.x86asm.net/coder64.html
--webで使えるアセンブラ・逆アセンブラ https://defuse.ca/o...
** (4) レジスタだけで計算するようにすれば、インタプリタで...
Mov_RI(R0,0);
Mov_RI(R1,0);
Lb_I(1); // L_1:
Add_RR(R0,R1); // R0 += R1;
Add_RI(R1,1); // R1 += 1;
CmpJlt_RII(R1,100000000,1); // if (R1 < 100000000) goto...
End(); // R0に計算結果が入っているので、それを表示して...
** (5) 理解を深めるためのQ&A
-[Q1]プログラムを見やすくするために以下の関数を導入してほ...
void set2(char *p, char a, char b) { p[0] = a; p[1] = b; }
void set3(char *p, char a, char b, char c) { p[0] = a; p...
void set4(char *p, char a, char b, char c, char d) { p[0...
void set5(char *p, char a, char b, char c, char d, char ...
--[A1]なるほど。それを使うとこうなります。
switch (tp->op) {
case Mov_RI: set2(&tx[rip + 0], 0x48, 0xb8 + tp->...
case Lod_RMD: set4(&tx[rip + 0], 0x48, 0x8b, 0x84 ...
case Sto_RMD: set4(&tx[rip + 0], 0x48, 0x89, 0x84 ...
case Add_RR: set3(&tx[rip + 0], 0x48, 0x03, 0xc0 ...
case Add_RI: set2(&tx[rip + 0], 0x48, 0xba); set6...
case Add_AI: set3(&tx[rip + 0], 0x48, 0x81, 0xc4 ...
case Sub_AI: set3(&tx[rip + 0], 0x48, 0x81, 0xc4 ...
case Lb_I: lb[tp->a] = rip; continue;
case CmpJlt_RII: set2(&tx[rip + 0], 0x48, 0xba); s...
set32(&tx[rip + 15], lb[tp->c] - (rip + 19)); ri...
case End: tx[rip + 0] = 0xc3; rip++; continue;
}
--たしかにだいぶ短くなりました。
-[Q2]この例では仮想的な機械語をインタプリタ実行したりJIT...
--[A2]その気になればもちろん誰でも作れますが、そうすると...
-[Q3]このプログラム例はWindows用になっていると思うのだけ...
--[A3]このプログラムでOS依存の部分は、mallocRWX()だけです...
-[Q4]このプログラムでは、Add_RI命令をRDX経由で実現してい...
--[A4]はい、そうです。じゃあそのように書き直してみますか...
case Add_RI:
if (-0x80000000LL <= tp->b && tp->b <= 0x7ffffff...
set3(&tx[rip + 0], 0x48, 0x81, 0xc0 + 0 * 8 + ...
} else {
set2(&tx[rip + 0], 0x48, 0xba); set64(&tx[rip ...
}
continue;
--どのくらい速くなったかなーと思いましたが、手元の環境で...
--もっとプログラムが大きくなってコードキャッシュの大きさ...
-[Q5]このJITコンパイラがシンプルなのって、RAX/RCX/RDXしか...
--[A5]そうですね、x64のABIはいろいろややこしいので、この...
-[Q6]なんか思ったよりもずいぶん短いのだけど、本当にこれで...
--[A6]いやインタプリタやJITコンパイラなんて結局この程度の...
--JITコンパイラが69行って思うかもしれないですけど、テスト...
-(以下思いついたら追記予定)
終了行:
* 「60分でできる!JITコンパイラ自作入門」
-(by [[K]], 2025.07.24)
** (0)
-JITコンパイラはインタプリタを高速にするために使われる定...
-たいして難しい技術ではないのですが、多くの人は難しいと漠...
-だから解説します。
-以下でも示しますが、普通のインタプリタをJITコンパイラに...
-JITコンパイラ化する以外で10倍も速くするのは相当に困難な...
-タイトルでは雑に60分とか書きましたが、ざっと理解するだけ...
** (1) 64bit-インタプリタ編 [61行]
-まず、以下のような命令セットを想定して、インタプリタとJI...
Sub_AI(SP,16); // SP = SP - 16;
Mov_RI(R0,0); // R0 = 0;
Sto_RMD(R0,SP,0); // [SP+0] = R0;
Sto_RMD(R0,SP,8); // [SP+8] = R0;
Lb_I(1); // L_1:
Lod_RMD(R0,SP,8); // R0 = [SP+8];
Lod_RMD(R1,SP,0); // R1 = [SP+0];
Add_RR(R0,R1); // R0 += R1;
Sto_RMD(R0,SP,0); // [SP+0] = R0;
Lod_RMD(R0,SP,8); // R0 = [SP+8];
Add_RI(R0,1); // R0 += 1;
Sto_RMD(R0,SP,8); // [SP+8] = R0;
CmpJlt_RII(R0,100000000,1); // if (R0 < 100000000) goto...
Lod_RMD(R0,SP,0); // R0 = [SP+0];
Add_AI(SP,16); // SP = SP + 16;
End(); // R0に計算結果が入っているので、それを表示して...
// ちなみに上記のコードは下記のソースコードをkccにコンパ...
// int s, i; s = 0;
// for (i = 0; i < 100000000; i++) { s = s + i; }
// つまり、0から99999999までの和を計算しています.
|Mov_RI(Rx,const);|整数レジスタ(Rx)に定数を代入|Rx = cons...
|Lod_RMD(Rx,Ax,disp);|メモリから値を読んで整数レジスタに...
|Sto_RMD(Rx,Ax,disp);|整数レジスタの値をメモリに書き込む|...
|Add_RR(Rx,Ry);|整数レジスタ同士の加算|Rx += Ry;|
|Add_RI(Rx,const);|整数レジスタに定数を加算|Rx += const;|
|Add_AI(Ax,const);|アドレスレジスタ(Ax)に定数を加算|Ax +=...
|Sub_AI(Ax,const);|アドレスレジスタに定数を減算|Ax -= con...
|Lb_I(x);|分岐先指定用のラベル定義命令(ラベルには名前は...
|CmpJlt_RII(Rx,const,y);|条件分岐命令|if (Rx < const) got...
|End();|R0の値を表示して終了||
-この10個の命令があれば上記は動きます。
-SPはA6レジスタの別名だということにします。
----
-ということでこんなプログラムを作りました。
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
struct Code { int64_t op, a, b, c; };
enum { Mov_RI=1, Lod_RMD, Sto_RMD, Add_RR, Add_RI, Add_A...
enum { R0=0, R1=1, SP=6 };
int main()
{
static struct Code t[17] = {
{ Sub_AI, SP, 16, -0 }, // -0は命令としては意味を持...
{ Mov_RI, R0, 0, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Sto_RMD, R0, SP, 8 },
{ Lb_I, 1, -0, -0 },
{ Lod_RMD, R0, SP, 8 },
{ Lod_RMD, R1, SP, 0 },
{ Add_RR, R0, R1, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Lod_RMD, R0, SP, 8 },
{ Add_RI, R0, 1, -0 },
{ Sto_RMD, R0, SP, 8 },
{ CmpJlt_RII, R0, 100000000, 1 },
{ Lod_RMD, R0, SP, 0 },
{ Add_AI, SP, 16, -0 },
{ End, -0, -0, -0 },
{ 0, -0, -0, -0 }
};
int64_t lb[256], r[8], a[8], pc;
char m[256]; // メモリ.
// Lb_I(x)命令を探して位置をlb[]に格納する.
for (pc = 0; t[pc].op > 0; pc++) {
if (t[pc].op == Lb_I) { lb[t[pc].a] = pc + 1; }
// 高速化のために、ラベル命令の次の命令の位置を登録...
}
// 実行開始.
pc = 0; a[6] = 256;
clock_t tm0 = clock();
for (;;) {
struct Code *tp = &t[pc]; int64_t *mp;
switch (tp->op) {
case Mov_RI: r[tp->a] = tp->b; pc++; continue;
case Lod_RMD: mp = (int64_t *) (m + a[tp->b] + tp->c...
case Sto_RMD: mp = (int64_t *) (m + a[tp->b] + tp->c...
case Add_RR: r[tp->a] += r[tp->b]; pc++; continue;
case Add_RI: r[tp->a] += tp->b; pc++; continue;
case Add_AI: a[tp->a] += tp->b; pc++; continue;
case Sub_AI: a[tp->a] -= tp->b; pc++; continue;
case Lb_I: pc++; continue;
case CmpJlt_RII: if (r[tp->a] < tp->b) { pc = lb[tp-...
case End: goto fin;
}
}
fin:
printf("R0=%" PRId64 " (%.3f[sec])\n", r[0], (clock() ...
return 0;
}
-実行すると R0=4999999950000000 と表示されます。
** (2) 64bit-JITコンパイラ編(x64用のコード生成) [69行]
-適当に作ればこんな感じです。
-Lod_RMD/Sto_RMD命令では、第二パラメータにSPしか指定しな...
-Sub_AI/Add_AI命令でも第一パラメータにSPしか指定しない想...
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
struct Code { int64_t op, a, b, c; };
enum { Mov_RI=1, Lod_RMD, Sto_RMD, Add_RR, Add_RI, Add_A...
enum { R0=0, R1=1, SP=6 };
#include <windows.h>
void *mallocRWX(int siz) { return VirtualAlloc(0, siz, M...
void set32(char *p, int64_t i) { p[0] = i & 0xff; p[1] =...
void set64(char *p, int64_t i) { set32(p, i); set32(p + ...
int main()
{
static struct Code t[17] = {
{ Sub_AI, SP, 16, -0 }, // -0は命令としては意味を持...
{ Mov_RI, R0, 0, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Sto_RMD, R0, SP, 8 },
{ Lb_I, 1, -0, -0 },
{ Lod_RMD, R0, SP, 8 },
{ Lod_RMD, R1, SP, 0 },
{ Add_RR, R0, R1, -0 },
{ Sto_RMD, R0, SP, 0 },
{ Lod_RMD, R0, SP, 8 },
{ Add_RI, R0, 1, -0 },
{ Sto_RMD, R0, SP, 8 },
{ CmpJlt_RII, R0, 100000000, 1 },
{ Lod_RMD, R0, SP, 0 },
{ Add_AI, SP, 16, -0 },
{ End, -0, -0, -0 },
{ 0, -0, -0, -0 }
};
int64_t lb[256], r[8], pc, pass, rip;
char *tx = mallocRWX(65536); // とりあえず64KB.
// 方針: R0はRAX, R1はRCXに割り当てる. SPはRSPに割り当...
// JITコンパイル開始.
for (pass = 0; pass < 2; pass++) { // あえて2回まわす.
rip = 0;
for (pc = 0; t[pc].op > 0; pc++) {
struct Code *tp = &t[pc];
switch (tp->op) {
case Mov_RI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Lod_RMD: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Sto_RMD: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Add_RR: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Add_RI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Add_AI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Sub_AI: tx[rip + 0] = 0x48; tx[rip + 1] = 0x...
case Lb_I: lb[tp->a] = rip; continue;
case CmpJlt_RII: tx[rip + 0] = 0x48; tx[rip + 1] =...
tx[rip + 13] = 0x0f; tx[rip + 14] = 0x8c; set32(...
case End: tx[rip + 0] = 0xc3; rip++; continue;
}
}
}
// int i; for (i = 0; i < rip; i++) printf("%02x ", ((...
// 実行開始.
int64_t (*f)() = (void *) tx;
clock_t tm0 = clock();
r[0] = f();
printf("R0=%" PRId64 " (%.3f[sec])\n", r[0], (clock() ...
return 0;
}
-当然ですが、実行すると R0=4999999950000000 と表示されま...
-変数passを使って、コード生成を2回やっています。これはほ...
-機械語を生成している部分は、まあ普通に見て意味不明だろう...
-そして10倍以上速いのです。
** (3) 今回使った機械語
48 bx [8バイト] : RAX/RCX/RDXに定数を代入. x=8:RAX, x=9:...
48 03 xx : レジスタをレジスタに加える演算( a += b; ). xx...
48 81 xx [4バイト] : レジスタと32bit整数定数の演算. 定数...
48 3b xx : レジスタ同士の比較.
0f 8c [4バイト] : 条件分岐(8cならJL)
c3 : return;
48 8b xx 24 [disp] : レジスタ=[RSP+disp]; xx=84+a*8.
48 89 xx 24 [disp] : [RSP+disp]=レジスタ; xx=84+a*8.
-参考にしたサイト(もし基礎的なことから勉強したいなら、以...
--REXプリフィックス https://www.wdic.org/w/SCI/REX%E3%83%...
--SIBバイト https://www.wdic.org/w/SCI/SIB%E3%83%90%E3%82...
--https://c9x.me/x86/
--http://ref.x86asm.net/coder64.html
--webで使えるアセンブラ・逆アセンブラ https://defuse.ca/o...
** (4) レジスタだけで計算するようにすれば、インタプリタで...
Mov_RI(R0,0);
Mov_RI(R1,0);
Lb_I(1); // L_1:
Add_RR(R0,R1); // R0 += R1;
Add_RI(R1,1); // R1 += 1;
CmpJlt_RII(R1,100000000,1); // if (R1 < 100000000) goto...
End(); // R0に計算結果が入っているので、それを表示して...
** (5) 理解を深めるためのQ&A
-[Q1]プログラムを見やすくするために以下の関数を導入してほ...
void set2(char *p, char a, char b) { p[0] = a; p[1] = b; }
void set3(char *p, char a, char b, char c) { p[0] = a; p...
void set4(char *p, char a, char b, char c, char d) { p[0...
void set5(char *p, char a, char b, char c, char d, char ...
--[A1]なるほど。それを使うとこうなります。
switch (tp->op) {
case Mov_RI: set2(&tx[rip + 0], 0x48, 0xb8 + tp->...
case Lod_RMD: set4(&tx[rip + 0], 0x48, 0x8b, 0x84 ...
case Sto_RMD: set4(&tx[rip + 0], 0x48, 0x89, 0x84 ...
case Add_RR: set3(&tx[rip + 0], 0x48, 0x03, 0xc0 ...
case Add_RI: set2(&tx[rip + 0], 0x48, 0xba); set6...
case Add_AI: set3(&tx[rip + 0], 0x48, 0x81, 0xc4 ...
case Sub_AI: set3(&tx[rip + 0], 0x48, 0x81, 0xc4 ...
case Lb_I: lb[tp->a] = rip; continue;
case CmpJlt_RII: set2(&tx[rip + 0], 0x48, 0xba); s...
set32(&tx[rip + 15], lb[tp->c] - (rip + 19)); ri...
case End: tx[rip + 0] = 0xc3; rip++; continue;
}
--たしかにだいぶ短くなりました。
-[Q2]この例では仮想的な機械語をインタプリタ実行したりJIT...
--[A2]その気になればもちろん誰でも作れますが、そうすると...
-[Q3]このプログラム例はWindows用になっていると思うのだけ...
--[A3]このプログラムでOS依存の部分は、mallocRWX()だけです...
-[Q4]このプログラムでは、Add_RI命令をRDX経由で実現してい...
--[A4]はい、そうです。じゃあそのように書き直してみますか...
case Add_RI:
if (-0x80000000LL <= tp->b && tp->b <= 0x7ffffff...
set3(&tx[rip + 0], 0x48, 0x81, 0xc0 + 0 * 8 + ...
} else {
set2(&tx[rip + 0], 0x48, 0xba); set64(&tx[rip ...
}
continue;
--どのくらい速くなったかなーと思いましたが、手元の環境で...
--もっとプログラムが大きくなってコードキャッシュの大きさ...
-[Q5]このJITコンパイラがシンプルなのって、RAX/RCX/RDXしか...
--[A5]そうですね、x64のABIはいろいろややこしいので、この...
-[Q6]なんか思ったよりもずいぶん短いのだけど、本当にこれで...
--[A6]いやインタプリタやJITコンパイラなんて結局この程度の...
--JITコンパイラが69行って思うかもしれないですけど、テスト...
-(以下思いついたら追記予定)
ページ名: