Binary Translation方式のエミュレータをRustで作る実装、浮動小数点命令を実装している。加減算命令については特に問題なく実装が進んだのだが、FMADDなどの3オペランド命令の実装についてサポートを追加した。FMADD.DなどのFused Multiply-Add命令は入力オペランドが3つ、出力オペランドが1つなので合計4オペランド必要だ。さらに第1引数として構造体へのポインタを渡すので合計5つの引数を渡す必要が生じる。これまでの実装では最大で4つまでの引数を渡せるようにしていたが、5つ目の引数は考えていなかったのだった。
調査していると、x86は以下の順番で引数をレジスタに設定するらしい。
- RDI, RSI, RDX, RCX, R8, R9
R8とR9ってなんだ?これらのレジスタをオペランドとして指定するためには拡張ビットを設定する必要があるらしい。いつもお世話になっている以下のページを参考にした。
ふむ、REX.Bというビットを設定するとR8/R9にアクセスできるようになるらしい。これはどのように設定するかというと、
いつも使っているREXプレフィックスの0ビット目を1に設定すればいいのか。なるほど。
という訳でR8レジスタを指定する際のオプションを実装した。
fn tcg_gen_imm_u64(dest: X86TargetRM, imm: u64, mc: &mut Vec<u8>) -> usize { let mut gen_size = 0; if dest == X86TargetRM::R8 { gen_size += Self::tcg_out(0x49, 1, mc); } else { gen_size += Self::tcg_out(0x48, 1, mc); } gen_size += Self::tcg_out(X86Opcode::MOV_EAX_IV as u64 + ((dest as u64) & 0x7), 1, mc); gen_size += Self::tcg_out(imm, 8, mc); gen_size }
とりあえずものすごく雑な実装になってしまった。。。R8/R9が指定されるとREX.Bビットを無理やりONにする。そしてレジスタ指定フィールドについてはレジスタ定義の下位3ビットだけを抽出して設定する。結果として以下のようなx86命令が生成される。
0x4001ce10be: 48 bf e0 ad 8a 01 40 00 movabsq $0x40018aade0, %rdi 0x4001ce10c6: 00 00 0x4001ce10c8: 48 be 03 00 00 00 00 00 movabsq $0x3, %rsi 0x4001ce10d0: 00 00 0x4001ce10d2: 48 ba 00 00 00 00 00 00 movabsq $0x0, %rdx 0x4001ce10da: 00 00 0x4001ce10dc: 48 b9 01 00 00 00 00 00 movabsq $0x1, %rcx 0x4001ce10e4: 00 00 0x4001ce10e6: 49 b8 02 00 00 00 00 00 movabsq $0x2, %r8 0x4001ce10ee: 00 00 0x4001ce10f0: ff 95 70 03 00 00 callq *0x370(%rbp)
r8
が浮動小数点演算のヘルパー関数における第5引数として動作する。これでFMADD.D fd,fs1,fs2,fs3
のすべての情報を渡せるようになった。テストを実行してみよう。
ans = 0x138 x00 = 0000000000000000 x01 = 0000000000000000 x02 = 0000000000000000 x03 = 0000000000000002 x04 = 0000000000000000 x05 = 0000000000000108 x06 = 000000000000b109 x07 = 0000000000000000 x08 = 0000000000000000 x09 = 0000000000000000 x10 = 400c000000000000 x11 = 0000000000000000 x12 = 0000000000000000 x13 = 400c000000000000 x14 = 0000000000000000 x15 = 0000000000000000 x16 = 0000000000000000 x17 = 0000000000000000 x18 = 0000000000000000 x19 = 0000000000000000 x20 = 0000000000000000 x21 = 0000000000000000 x22 = 0000000000000000 x23 = 0000000000000000 x24 = 0000000000000000 x25 = 0000000000000000 x26 = 0000000000000000 x27 = 0000000000000000 x28 = 0000000000000000 x29 = 0000000000000000 x30 = 0000000000000000 x31 = 0000000000000000 f00 = 3ff0000000000000 f01 = 4004000000000000 f02 = 3ff0000000000000 f03 = 400c000000000000 f04 = 0000000000000000 f05 = 0000000000000000 f06 = 0000000000000000 f07 = 0000000000000000 f08 = 0000000000000000 f09 = 0000000000000000 f10 = 0000000000000000 f11 = 0000000000000000 f12 = 0000000000000000 f13 = 0000000000000000 f14 = 0000000000000000 f15 = 0000000000000000 f16 = 0000000000000000 f17 = 0000000000000000 f18 = 0000000000000000 f19 = 0000000000000000 f20 = 0000000000000000 f21 = 0000000000000000 f22 = 0000000000000000 f23 = 0000000000000000 f24 = 0000000000000000 f25 = 0000000000000000 f26 = 0000000000000000 f27 = 0000000000000000 f28 = 0000000000000000 f29 = 0000000000000000 f30 = 0000000000000000 f31 = 0000000000000000
良さそうだ。FMADD系のテストパタンはすべてPassできることを確認した。