#[macro_use]
mod macros;
use crate::{Const, FloatBinOp, FloatUnaryOp, Inst, IntBinOp, IntUnaryOp, Optimizer};
impl Optimizer {
pub(super) fn fold_consts(&mut self, insts: Vec<Inst>) -> Vec<Inst> {
let mut new_insts = Vec::with_capacity(insts.len());
for inst in insts {
if let Some(Inst::Const { value, dst }) = self.try_fold(&inst) {
self.const_map.insert(dst, value);
new_insts.push(Inst::Const { value, dst });
} else {
new_insts.push(inst);
}
}
new_insts
}
fn try_fold(&self, inst: &Inst) -> Option<Inst> {
match inst {
Inst::IBinOp { op, lhs, rhs, dst } => {
let lhs_const = *self.const_map.get(lhs)?;
let rhs_const = *self.const_map.get(rhs)?;
Some(Inst::Const {
value: fold_ibinop(op, lhs_const, rhs_const)?,
dst: *dst,
})
}
Inst::IUnaryOp { op, operand, dst } => {
let operand_const = *self.const_map.get(operand)?;
Some(Inst::Const {
value: fold_iunaryop(op, operand_const)?,
dst: *dst,
})
}
Inst::FBinOp { op, lhs, rhs, dst } => {
let lhs_const = *self.const_map.get(lhs)?;
let rhs_const = *self.const_map.get(rhs)?;
Some(Inst::Const {
value: fold_fbinop(op, lhs_const, rhs_const)?,
dst: *dst,
})
}
Inst::FUnaryOp { op, operand, dst } => {
let operand_const = *self.const_map.get(operand)?;
Some(Inst::Const {
value: fold_funaryop(op, operand_const)?,
dst: *dst,
})
}
_ => None,
}
}
}
fn fold_ibinop(op: &IntBinOp, lhs: Const, rhs: Const) -> Option<Const> {
match (lhs, rhs) {
(Const::I8(l), Const::I8(r)) => apply_ibinop!(op, l, r, u8).map(Const::I8),
(Const::I16(l), Const::I16(r)) => apply_ibinop!(op, l, r, u16).map(Const::I16),
(Const::I32(l), Const::I32(r)) => apply_ibinop!(op, l, r, u32).map(Const::I32),
(Const::I64(l), Const::I64(r)) => apply_ibinop!(op, l, r, u64).map(Const::I64),
_ => None,
}
}
fn fold_iunaryop(op: &IntUnaryOp, val: Const) -> Option<Const> {
match val {
Const::I8(v) => Some(Const::I8(apply_iunaryop!(op, v))),
Const::I16(v) => Some(Const::I16(apply_iunaryop!(op, v))),
Const::I32(v) => Some(Const::I32(apply_iunaryop!(op, v))),
Const::I64(v) => Some(Const::I64(apply_iunaryop!(op, v))),
_ => None,
}
}
fn fold_fbinop(op: &FloatBinOp, lhs: Const, rhs: Const) -> Option<Const> {
match (lhs, rhs) {
(Const::F32(l), Const::F32(r)) => Some(Const::F32(apply_fbinop!(op, l, r))),
(Const::F64(l), Const::F64(r)) => Some(Const::F64(apply_fbinop!(op, l, r))),
_ => None,
}
}
fn fold_funaryop(op: &FloatUnaryOp, val: Const) -> Option<Const> {
match val {
Const::F32(v) => Some(Const::F32(apply_funaryop!(op, v))),
Const::F64(v) => Some(Const::F64(apply_funaryop!(op, v))),
_ => None,
}
}