私は、独自の仮想マシン用にコンパイルするスクリプト言語を開発しています。これは、ポイント、ベクトル、フロートなどのある種のデータを処理する命令を持つ単純な言語です。メモリセルは次のように表されます。
struct memory_cell
{
u32 id;
u8 type;
union
{
u8 b; /* boolean */
double f; /* float */
struct { double x, y, z; } v; /* vector */
struct { double r, g, b; } c; /* color */
struct { double r, g, b; } cw; /* color weight */
struct { double x, y, z; } p; /* point variable */
struct { u16 length; memory_cell **cells; } l; /* list variable */
};
};
命令は一般的であり、多くの異なるオペランドで機能します。例えば
ADD dest, src1, src2
オペランドに応じて適切な宛先のタイプを設定するフロート、ベクトル、ポイント、カラーを操作できます。
メインの実行サイクルは、命令のオペコード(あらゆる種類の命令を定義するためのユニオンを含む構造体)をチェックして実行するだけです。私は、レジスターを持たず、メモリーセルの大きな配列だけを持っている単純化されたアプローチを使用しました。
JITが最高のパフォーマンスを得るのに役立つかどうか、そしてそれをどのように達成するかを考えていました。
私が言ったように、これまでに到達した最良の実装は次のようなものです。
void VirtualMachine::executeInstruction(instr i)
{
u8 opcode = (i.opcode[0] & (u8)0xFC) >> 2;
if (opcode >= 1 && opcode <= 17) /* RTL instruction */
{
memory_cell *dest;
memory_cell *src1;
memory_cell *src2;
/* fetching destination */
switch (i.opcode[0] & 0x03)
{
/* skip fetching for optimization */
case 0: { break; }
case MEM_CELL: { dest = memory[stack_pointer+i.rtl.dest.cell]; break; }
case ARRAY_VAL: { dest = memory[stack_pointer+i.rtl.dest.cell]->l.cells[i.rtl.dest.index]; break; }
case ARRAY_CELL: { dest = memory[stack_pointer+i.rtl.dest.cell]->l.cells[(int)i.rtl.dest.value]; break; }
}
/* omitted code */
switch (opcode)
{
case ADD:
{
if (src1->type == M_VECTOR && src2->type == M_VECTOR)
{
dest->type = M_VECTOR;
dest->v.x = src1->v.x + src2->v.x;
dest->v.y = src1->v.y + src2->v.y;
dest->v.z = src1->v.z + src2->v.z;
}
/* omitted code */
jitコンパイルを試すのは簡単/便利ですか?しかし、私は本当にどこから始めればよいのかわからないので、私はいくつかのアドバイスを求めています。
それとは別に、それを開発する際に考慮すべき他のアドバイスはありますか?
この仮想マシンは、レイトレーサーのシェーダーを計算するのに十分な速度である必要がありますが、私はどのような種類のベンチマークも実行していません。