rv8というのはRISC-VのデコーダやJITエンジンなどをまとめたパッケージで、Sniperサイクル精度シミュレータはrv8をデコードエンジンとして使用している。 Sniperでのサイクル計算の中で、どうも16ビットのC拡張をうまくデコードすることができていないように見えたのでその解析をした。
sniper/decoder_lib/riscv_decoder.cc
void RISCVDecoder::decode(DecodedInst * inst) /* ... 途中省略 ... */ riscv::decode_inst_rv64(dec, r_inst); decode_inst_type(dec, r_inst); decode_pseudo_inst(dec);
decode_inst_rv64
で、RV64モードでの命令のデコードを行う。decompress_inst_rv64
で、C拡張の16ビット命令を32ビットの命令に変換する。
template <typename T> inline void decode_inst_rv64(T &dec, inst_t inst) { decode_inst<T,false,true,false>(dec, inst); decompress_inst_rv64<T>(dec); }
decode_inst_type()
によって、命令のデコードを行う。
rv8/src/asm/switch.h
template <typename T> inline void decode_inst_type(T &dec, riscv::inst_t inst) { dec.codec = rv_inst_codec[dec.op]; switch (dec.codec) { case rv_codec_none: riscv::decode_none(dec, inst); break; case rv_codec_u: riscv::decode_u(dec, inst); break; case rv_codec_uj: riscv::decode_uj(dec, inst); break; case rv_codec_i: riscv::decode_i(dec, inst); break; case rv_codec_i_sh5: riscv::decode_i_sh5(dec, inst); break; case rv_codec_i_sh6: riscv::decode_i_sh6(dec, inst); break; case rv_codec_i_sh7: riscv::decode_i_sh7(dec, inst); break; case rv_codec_i_csr: riscv::decode_i_csr(dec, inst); break; case rv_codec_s: riscv::decode_s(dec, inst); break; case rv_codec_sb: riscv::decode_sb(dec, inst); break; case rv_codec_r: riscv::decode_r(dec, inst); break; case rv_codec_r_m: riscv::decode_r_m(dec, inst); break;
rv8/src/asm/decode.h
/* Decode I */ template <typename T> inline void decode_i(T &dec, inst_t inst) { dec.rd = operand_rd::decode(inst); dec.rs1 = operand_rs1::decode(inst); dec.rs2 = rv_ireg_zero; dec.imm = operand_imm12::decode(inst); }
問題はこの時、C拡張の機械語のままこのデコードを適用してしまうので、例えばdec.imm
の値はそのまま再利用することができない。
これによって、さらに最適化の機能が働いてしまい、命令が変換されてしまう。例えばc.addi
でオペランドが誤って0に認識されてしまい、mv
命令に変換されてしまう。
rv8/src/asm/meta.cc
const rv_comp_data rvcd_rv64_addi[] = { { rv_op_c_addi4spn, rvcc_c_addi4spn }, { rv_op_c_nop, rvcc_c_nop }, { rv_op_c_addi, rvcc_c_addi }, { rv_op_c_li, rvcc_c_li }, { rv_op_c_addi16sp, rvcc_c_addi16sp }, { rv_op_c_mv, rvcc_c_mv }, { rv_op_illegal, nullptr } };
したがって、とりあえずC拡張がうまくデコードされない問題を解決したい場合は、デコード以下の最適化を省略すればいい。
riscv::decode_inst_rv64(dec, r_inst); // decode_inst_type(dec, r_inst); // decode_pseudo_inst(dec);