use super::instruction::*;
use crate::common::InstructionBuilder;
#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
pub struct Riscv64InstructionBuilder {
instructions: Vec<Instruction>,
#[cfg(feature = "register-tracking")]
register_usage: crate::common::register_usage::RegisterUsageInfo<Register>,
}
impl Riscv64InstructionBuilder {
pub fn new() -> Self {
Self {
instructions: Vec::new(),
#[cfg(feature = "register-tracking")]
register_usage: crate::common::register_usage::RegisterUsageInfo::new(),
}
}
#[cfg(feature = "register-tracking")]
fn track_written_register(&mut self, reg: Register) {
self.register_usage.add_written_register(reg);
}
#[cfg(feature = "register-tracking")]
fn track_read_register(&mut self, reg: Register) {
self.register_usage.add_read_register(reg);
}
#[cfg(feature = "register-tracking")]
fn track_read_registers(&mut self, regs: &[Register]) {
for ® in regs {
self.register_usage.add_read_register(reg);
}
}
#[cfg(not(feature = "register-tracking"))]
fn track_written_register(&mut self, _reg: Register) {
}
#[cfg(not(feature = "register-tracking"))]
fn track_read_register(&mut self, _reg: Register) {
}
#[cfg(not(feature = "register-tracking"))]
fn track_read_registers(&mut self, _regs: &[Register]) {
}
fn encode_r_type_tracked(&mut self, opcode: u8, rd: Register, funct3: u8, rs1: Register, rs2: Register, funct7: u8) -> Instruction {
self.track_written_register(rd);
self.track_read_registers(&[rs1, rs2]);
encode_r_type(opcode, rd, funct3, rs1, rs2, funct7)
}
fn encode_i_type_tracked(&mut self, opcode: u8, rd: Register, funct3: u8, rs1: Register, imm: i16) -> Instruction {
self.track_written_register(rd);
self.track_read_register(rs1);
encode_i_type(opcode, rd, funct3, rs1, imm)
}
fn encode_s_type_tracked(&mut self, opcode: u8, funct3: u8, rs1: Register, rs2: Register, imm: i16) -> Instruction {
self.track_read_registers(&[rs1, rs2]);
encode_s_type(opcode, funct3, rs1, rs2, imm)
}
fn encode_b_type_tracked(&mut self, opcode: u8, funct3: u8, rs1: Register, rs2: Register, imm: i16) -> Instruction {
self.track_read_registers(&[rs1, rs2]);
encode_b_type(opcode, funct3, rs1, rs2, imm)
}
fn encode_u_type_tracked(&mut self, opcode: u8, rd: Register, imm: u32) -> Instruction {
self.track_written_register(rd);
encode_u_type(opcode, rd, imm)
}
fn encode_j_type_tracked(&mut self, opcode: u8, rd: Register, imm: i32) -> Instruction {
self.track_written_register(rd);
encode_j_type(opcode, rd, imm)
}
fn encode_csr_type_tracked(&mut self, opcode: u8, rd: Register, funct3: u8, rs1: Register, csr: Csr) -> Instruction {
self.track_written_register(rd);
self.track_read_register(rs1);
encode_csr_type(opcode, rd, funct3, rs1, csr)
}
fn encode_csr_imm_type_tracked(&mut self, opcode: u8, rd: Register, funct3: u8, uimm: u8, csr: Csr) -> Instruction {
self.track_written_register(rd);
encode_csr_imm_type(opcode, rd, funct3, uimm, csr)
}
pub fn raw_instructions(&self) -> &[Instruction] {
&self.instructions
}
pub fn push(&mut self, instr: Instruction) -> &mut Self {
self.instructions.push(instr);
self
}
pub fn clear(&mut self) -> &mut Self {
self.instructions.clear();
#[cfg(feature = "register-tracking")]
self.register_usage.clear();
self
}
}
impl InstructionBuilder<Instruction> for Riscv64InstructionBuilder {
type Register = Register;
fn new() -> Self {
Self {
instructions: Vec::new(),
#[cfg(feature = "register-tracking")]
register_usage: crate::common::register_usage::RegisterUsageInfo::new(),
}
}
fn instructions(&self) -> crate::common::InstructionCollection<Instruction> {
crate::common::InstructionCollection::from_slice(&self.instructions)
}
fn push(&mut self, instr: Instruction) {
self.instructions.push(instr);
}
fn clear(&mut self) {
self.instructions.clear();
#[cfg(feature = "register-tracking")]
self.register_usage.clear();
}
#[cfg(feature = "register-tracking")]
fn register_usage(&self) -> &crate::common::register_usage::RegisterUsageInfo<Self::Register> {
&self.register_usage
}
#[cfg(feature = "register-tracking")]
fn register_usage_mut(&mut self) -> &mut crate::common::register_usage::RegisterUsageInfo<Self::Register> {
&mut self.register_usage
}
#[cfg(feature = "std")]
unsafe fn function<F>(&self) -> Result<crate::common::jit::CallableJitFunction<F>, crate::common::jit::JitError> {
let code = self.instructions().to_bytes();
crate::common::jit::CallableJitFunction::<F>::new(&code)
}
#[cfg(feature = "std")]
unsafe fn raw_function(&self) -> Result<crate::common::jit::RawCallableJitFunction, crate::common::jit::JitError> {
let code = self.instructions().to_bytes();
crate::common::jit::RawCallableJitFunction::new(&code)
}
}
impl Riscv64InstructionBuilder {
pub fn csrrw(&mut self, rd: Register, csr: Csr, rs1: Register) -> &mut Self {
let instr = self.encode_csr_type_tracked(opcodes::SYSTEM, rd, system_funct3::CSRRW, rs1, csr);
self.push(instr);
self
}
pub fn csrrs(&mut self, rd: Register, csr: Csr, rs1: Register) -> &mut Self {
let instr = self.encode_csr_type_tracked(opcodes::SYSTEM, rd, system_funct3::CSRRS, rs1, csr);
self.push(instr);
self
}
pub fn csrrc(&mut self, rd: Register, csr: Csr, rs1: Register) -> &mut Self {
let instr = self.encode_csr_type_tracked(opcodes::SYSTEM, rd, system_funct3::CSRRC, rs1, csr);
self.push(instr);
self
}
pub fn csrrwi(&mut self, rd: Register, csr: Csr, uimm: u8) -> &mut Self {
let instr = self.encode_csr_imm_type_tracked(opcodes::SYSTEM, rd, system_funct3::CSRRWI, uimm, csr);
self.push(instr);
self
}
pub fn csrrsi(&mut self, rd: Register, csr: Csr, uimm: u8) -> &mut Self {
let instr = self.encode_csr_imm_type_tracked(opcodes::SYSTEM, rd, system_funct3::CSRRSI, uimm, csr);
self.push(instr);
self
}
pub fn csrrci(&mut self, rd: Register, csr: Csr, uimm: u8) -> &mut Self {
let instr = self.encode_csr_imm_type_tracked(opcodes::SYSTEM, rd, system_funct3::CSRRCI, uimm, csr);
self.push(instr);
self
}
pub fn csrr(&mut self, rd: Register, csr: Csr) -> &mut Self {
self.csrrs(rd, csr, super::reg::X0)
}
pub fn csrw(&mut self, csr: Csr, rs1: Register) -> &mut Self {
self.csrrw(super::reg::X0, csr, rs1)
}
pub fn csrs(&mut self, csr: Csr, rs1: Register) -> &mut Self {
self.csrrs(super::reg::X0, csr, rs1)
}
pub fn csrc(&mut self, csr: Csr, rs1: Register) -> &mut Self {
self.csrrc(super::reg::X0, csr, rs1)
}
pub fn csrwi(&mut self, csr: Csr, uimm: u8) -> &mut Self {
self.csrrwi(super::reg::X0, csr, uimm)
}
pub fn csrsi(&mut self, csr: Csr, uimm: u8) -> &mut Self {
self.csrrsi(super::reg::X0, csr, uimm)
}
pub fn csrci(&mut self, csr: Csr, uimm: u8) -> &mut Self {
self.csrrci(super::reg::X0, csr, uimm)
}
pub fn add(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::ADD_SUB, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn addi(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::ADD_SUB, rs1, imm);
self.push(instr);
self
}
pub fn sub(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::ADD_SUB, rs1, rs2, 0x20);
self.push(instr);
self
}
pub fn subi(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::ADD_SUB, rs1, -imm);
self.push(instr);
self
}
pub fn xor(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::XOR, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn xori(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::XOR, rs1, imm);
self.push(instr);
self
}
pub fn or(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::OR, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn ori(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::OR, rs1, imm);
self.push(instr);
self
}
pub fn slt(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::SLT, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn slti(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::SLT, rs1, imm);
self.push(instr);
self
}
pub fn sltu(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::SLTU, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn sltiu(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::SLTU, rs1, imm);
self.push(instr);
self
}
pub fn sll(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::SLL, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn srl(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::SRL_SRA, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn sra(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::SRL_SRA, rs1, rs2, 0x20);
self.push(instr);
self
}
pub fn slli(&mut self, rd: Register, rs1: Register, shamt: u8) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::SLL, rs1, shamt as i16);
self.push(instr);
self
}
pub fn srli(&mut self, rd: Register, rs1: Register, shamt: u8) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::SRL_SRA, rs1, shamt as i16);
self.push(instr);
self
}
pub fn srai(&mut self, rd: Register, rs1: Register, shamt: u8) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::SRL_SRA, rs1, (shamt as i16) | 0x400);
self.push(instr);
self
}
pub fn and(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, alu_funct3::AND, rs1, rs2, 0x0);
self.push(instr);
self
}
pub fn andi(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::OP_IMM, rd, alu_funct3::AND, rs1, imm);
self.push(instr);
self
}
pub fn mul(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::MUL, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn mulh(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::MULH, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn mulhsu(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::MULHSU, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn mulhu(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::MULHU, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn div(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::DIV, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn divu(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::DIVU, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn rem(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::REM, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn remu(&mut self, rd: Register, rs1: Register, rs2: Register) -> &mut Self {
let instr = self.encode_r_type_tracked(opcodes::OP, rd, m_funct3::REMU, rs1, rs2, m_funct7::M_EXT);
self.push(instr);
self
}
pub fn ld(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LD, rs1, imm);
self.push(instr);
self
}
pub fn lw(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LW, rs1, imm);
self.push(instr);
self
}
pub fn lh(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LH, rs1, imm);
self.push(instr);
self
}
pub fn lb(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LB, rs1, imm);
self.push(instr);
self
}
pub fn lbu(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LBU, rs1, imm);
self.push(instr);
self
}
pub fn lhu(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LHU, rs1, imm);
self.push(instr);
self
}
pub fn lwu(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::LOAD, rd, load_funct3::LWU, rs1, imm);
self.push(instr);
self
}
pub fn li(&mut self, rd: Register, imm: i32) -> &mut Self {
let upper = (imm + 0x800) >> 12; let lower = imm & 0xfff;
if upper != 0 {
self.lui(rd, upper as u32);
}
if lower != 0 || upper == 0 {
if upper == 0 {
self.addi(rd, super::reg::X0, lower as i16);
} else {
self.addi(rd, rd, lower as i16);
}
}
self
}
pub fn sd(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_s_type_tracked(opcodes::STORE, store_funct3::SD, rs1, rs2, imm);
self.push(instr);
self
}
pub fn sw(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_s_type_tracked(opcodes::STORE, store_funct3::SW, rs1, rs2, imm);
self.push(instr);
self
}
pub fn sh(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_s_type_tracked(opcodes::STORE, store_funct3::SH, rs1, rs2, imm);
self.push(instr);
self
}
pub fn sb(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_s_type_tracked(opcodes::STORE, store_funct3::SB, rs1, rs2, imm);
self.push(instr);
self
}
pub fn lui(&mut self, rd: Register, imm: u32) -> &mut Self {
let instr = self.encode_u_type_tracked(opcodes::LUI, rd, imm);
self.push(instr);
self
}
pub fn auipc(&mut self, rd: Register, imm: u32) -> &mut Self {
let instr = self.encode_u_type_tracked(opcodes::AUIPC, rd, imm);
self.push(instr);
self
}
pub fn jal(&mut self, rd: Register, imm: i32) -> &mut Self {
let instr = self.encode_j_type_tracked(opcodes::JAL, rd, imm);
self.push(instr);
self
}
pub fn jalr(&mut self, rd: Register, rs1: Register, imm: i16) -> &mut Self {
let instr = self.encode_i_type_tracked(opcodes::JALR, rd, 0x0, rs1, imm);
self.push(instr);
self
}
pub fn beq(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_b_type_tracked(opcodes::BRANCH, branch_funct3::BEQ, rs1, rs2, imm);
self.push(instr);
self
}
pub fn bne(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_b_type_tracked(opcodes::BRANCH, branch_funct3::BNE, rs1, rs2, imm);
self.push(instr);
self
}
pub fn blt(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_b_type_tracked(opcodes::BRANCH, branch_funct3::BLT, rs1, rs2, imm);
self.push(instr);
self
}
pub fn bge(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_b_type_tracked(opcodes::BRANCH, branch_funct3::BGE, rs1, rs2, imm);
self.push(instr);
self
}
pub fn bltu(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_b_type_tracked(opcodes::BRANCH, branch_funct3::BLTU, rs1, rs2, imm);
self.push(instr);
self
}
pub fn bgeu(&mut self, rs1: Register, rs2: Register, imm: i16) -> &mut Self {
let instr = self.encode_b_type_tracked(opcodes::BRANCH, branch_funct3::BGEU, rs1, rs2, imm);
self.push(instr);
self
}
pub fn sret(&mut self) -> &mut Self {
let instr = super::instruction::encode_privileged_type(
super::instruction::opcodes::SYSTEM,
super::instruction::privileged_funct12::SRET
);
self.push(instr);
self
}
pub fn mret(&mut self) -> &mut Self {
let instr = super::instruction::encode_privileged_type(
super::instruction::opcodes::SYSTEM,
super::instruction::privileged_funct12::MRET
);
self.push(instr);
self
}
pub fn ecall(&mut self) -> &mut Self {
let instr = super::instruction::encode_privileged_type(
super::instruction::opcodes::SYSTEM,
super::instruction::privileged_funct12::ECALL
);
self.push(instr);
self
}
pub fn ebreak(&mut self) -> &mut Self {
let instr = super::instruction::encode_privileged_type(
super::instruction::opcodes::SYSTEM,
super::instruction::privileged_funct12::EBREAK
);
self.push(instr);
self
}
pub fn wfi(&mut self) -> &mut Self {
let instr = super::instruction::encode_privileged_type(
super::instruction::opcodes::SYSTEM,
super::instruction::privileged_funct12::WFI
);
self.push(instr);
self
}
pub fn ret(&mut self) -> &mut Self {
self.jalr(super::reg::X0, super::reg::X1, 0)
}
}