use super::{Executor, InstructionPtr};
use crate::{
core::UntypedVal,
engine::{
bytecode::{AnyConst32, Const32, Instruction, Reg},
utils::unreachable_unchecked,
},
};
impl<'engine> Executor<'engine> {
fn fetch_register_2(&self) -> (Reg, Reg) {
let mut addr: InstructionPtr = self.ip;
addr.add(1);
match *addr.get() {
Instruction::Register2 { regs: [reg0, reg1] } => (reg0, reg1),
unexpected => {
unsafe {
unreachable_unchecked!(
"expected `Instruction::Register2` but found {unexpected:?}"
)
}
}
}
}
fn fetch_register_and_imm32<T>(&self) -> (Reg, T)
where
T: From<AnyConst32>,
{
let mut addr: InstructionPtr = self.ip;
addr.add(1);
match *addr.get() {
Instruction::RegisterAndImm32 { reg, imm } => (reg, T::from(imm)),
unexpected => {
unsafe {
unreachable_unchecked!(
"expected `Instruction::RegisterAndImm32` but found {unexpected:?}"
)
}
}
}
}
fn execute_select_impl<L, R>(
&mut self,
result: Reg,
condition: Reg,
lhs: impl FnOnce(&Self) -> L,
rhs: impl FnOnce(&Self) -> R,
) where
L: Into<UntypedVal>,
R: Into<UntypedVal>,
{
let condition: bool = self.get_register_as(condition);
let selected = match condition {
true => lhs(self).into(),
false => rhs(self).into(),
};
self.set_register(result, selected);
self.next_instr_at(2);
}
pub fn execute_select(&mut self, result: Reg, lhs: Reg) {
let (condition, rhs) = self.fetch_register_2();
self.execute_select_impl(
result,
condition,
|this| this.get_register(lhs),
|this| this.get_register(rhs),
)
}
pub fn execute_select_imm32_rhs(&mut self, result: Reg, lhs: Reg) {
let (condition, rhs) = self.fetch_register_and_imm32::<AnyConst32>();
self.execute_select_impl(
result,
condition,
|this: &Executor<'engine>| this.get_register(lhs),
|_| u32::from(rhs),
)
}
pub fn execute_select_imm32_lhs(&mut self, result: Reg, lhs: AnyConst32) {
let (condition, rhs) = self.fetch_register_2();
self.execute_select_impl(
result,
condition,
|_| u32::from(lhs),
|this| this.get_register(rhs),
)
}
pub fn execute_select_imm32(&mut self, result: Reg, lhs: AnyConst32) {
let (condition, rhs) = self.fetch_register_and_imm32::<AnyConst32>();
self.execute_select_impl(result, condition, |_| u32::from(lhs), |_| u32::from(rhs))
}
pub fn execute_select_i64imm32_rhs(&mut self, result: Reg, lhs: Reg) {
let (condition, rhs) = self.fetch_register_and_imm32::<i32>();
self.execute_select_impl(
result,
condition,
|this| this.get_register(lhs),
|_| i64::from(rhs),
)
}
pub fn execute_select_i64imm32_lhs(&mut self, result: Reg, lhs: Const32<i64>) {
let (condition, rhs) = self.fetch_register_2();
self.execute_select_impl(
result,
condition,
|_| i64::from(lhs),
|this| this.get_register(rhs),
)
}
pub fn execute_select_i64imm32(&mut self, result: Reg, lhs: Const32<i64>) {
let (condition, rhs) = self.fetch_register_and_imm32::<i32>();
self.execute_select_impl(result, condition, |_| i64::from(lhs), |_| i64::from(rhs))
}
pub fn execute_select_f64imm32_rhs(&mut self, result: Reg, lhs: Reg) {
let (condition, rhs) = self.fetch_register_and_imm32::<f32>();
self.execute_select_impl(
result,
condition,
|this| this.get_register(lhs),
|_| f64::from(rhs),
)
}
pub fn execute_select_f64imm32_lhs(&mut self, result: Reg, lhs: Const32<f64>) {
let (condition, rhs) = self.fetch_register_2();
self.execute_select_impl(
result,
condition,
|_| f64::from(lhs),
|this| this.get_register(rhs),
)
}
pub fn execute_select_f64imm32(&mut self, result: Reg, lhs: Const32<f64>) {
let (condition, rhs) = self.fetch_register_and_imm32::<f32>();
self.execute_select_impl(result, condition, |_| f64::from(lhs), |_| f64::from(rhs))
}
}