use crate::{
Block, Const, FloatBinOp, FloatUnaryOp, IRBuilder, IRType, Inst, IntBinOp, IntUnaryOp, Offset,
Value, Variable,
inst::{FloatCmp, IntCmp},
};
pub trait InstBuilder {
fn alloc(&mut self, size: u32, align: u32) -> Value;
fn load(&mut self, ty: IRType, src_ptr: Value, src_offset: Offset) -> Value;
fn store(&mut self, src: Value, dst_ptr: Value, dst_offset: Offset);
fn memcpy(&mut self, size: u32, src_ptr: Value, dst_ptr: Value);
fn memset(&mut self, size: u32, value: u8, dst_ptr: Value);
fn const_val(&mut self, const_val: Const) -> Value;
fn assign(&mut self, var: Variable, src: Value);
fn load_var(&mut self, var: Variable) -> Value;
fn jump(&mut self, block: Block, args: &[Value]);
fn brif(
&mut self,
cond: Value,
then_block: Block,
then_args: &[Value],
else_block: Block,
else_args: &[Value],
);
fn _return(&mut self, vals: &[Value]);
fn select(&mut self, cond: Value, then_val: Value, else_val: Value) -> Value;
fn iresize(&mut self, src: Value, dst_ty: IRType) -> Value;
fn fresize(&mut self, src: Value, dst_ty: IRType) -> Value;
fn itof(&mut self, src: Value) -> Value;
fn ftoi(&mut self, src: Value) -> Value;
fn ptr_add(&mut self, ptr: Value, offset: Offset) -> Value;
fn ibop(&mut self, op: IntBinOp, lhs: Value, rhs: Value) -> Value;
fn fbop(&mut self, op: FloatBinOp, lhs: Value, rhs: Value) -> Value;
fn iuop(&mut self, op: IntUnaryOp, operand: Value) -> Value;
fn fuop(&mut self, op: FloatUnaryOp, operand: Value) -> Value;
fn icmp(&mut self, cmp: IntCmp, lhs: Value, rhs: Value) -> Value;
fn fcmp(&mut self, cmp: FloatCmp, lhs: Value, rhs: Value) -> Value;
fn icmp_imm(&mut self, cmp: IntCmp, lhs: Value, rhs: i64) -> Value;
}
impl InstBuilder for IRBuilder {
fn alloc(&mut self, size: u32, align: u32) -> Value {
let dst = self.create_val(IRType::Ptr);
self.push_inst(Inst::Alloc { size, align, dst });
dst
}
fn load(&mut self, ty: IRType, src_ptr: Value, src_offset: Offset) -> Value {
let dst = self.create_val(ty);
self.push_inst(Inst::Load {
ty,
src_ptr,
src_offset,
dst,
});
dst
}
fn store(&mut self, src: Value, dst_ptr: Value, dst_offset: Offset) {
self.push_inst(Inst::Store {
src,
dst_ptr,
dst_offset,
});
}
fn memcpy(&mut self, size: u32, src_ptr: Value, dst_ptr: Value) {
assert!(
self.is_val_type(dst_ptr, IRType::Ptr),
"Type of the memcpy destination pointer is not pointer type"
);
assert!(
self.is_val_type(src_ptr, IRType::Ptr),
"Type of the memcpy source pointer is not pointer type"
);
self.push_inst(Inst::Memcpy {
size,
src_ptr,
dst_ptr,
});
}
fn memset(&mut self, size: u32, value: u8, dst_ptr: Value) {
self.push_inst(Inst::Memset {
size,
value,
dst_ptr,
});
}
fn const_val(&mut self, const_val: Const) -> Value {
let dst = self.create_val(const_val.get_type());
self.push_inst(Inst::Const {
value: const_val,
dst,
});
dst
}
fn assign(&mut self, var: Variable, src: Value) {
let var_ty = self.get_var_type(var);
assert!(
self.is_val_type(src, var_ty),
"Type of the assign source value does not match the variable type {}",
var_ty
);
self.push_inst(Inst::Assign { var, src });
}
fn load_var(&mut self, var: Variable) -> Value {
let var_ty = self.get_var_type(var);
let dst = self.create_val(var_ty);
self.push_inst(Inst::LoadVar { var, dst });
dst
}
fn jump(&mut self, block: Block, args: &[Value]) {
self.push_inst(Inst::Jump {
block,
args: args.to_vec(),
});
}
fn brif(
&mut self,
cond: Value,
then_block: Block,
then_args: &[Value],
else_block: Block,
else_args: &[Value],
) {
assert!(
self.is_val_type(cond, IRType::I8),
"Type of the brif condition value must be 8-bit integer type"
);
self.push_inst(Inst::Brif {
cond,
then_block,
then_args: then_args.to_vec(),
else_block,
else_args: else_args.to_vec(),
});
}
fn _return(&mut self, vals: &[Value]) {
self.push_inst(Inst::Return {
vals: vals.to_vec(),
});
}
fn select(&mut self, cond: Value, then_val: Value, else_val: Value) -> Value {
assert!(
self.is_val_type(cond, IRType::I8),
"Type of the select condition value must be 8-bit integer type"
);
let then_ty = self.get_val_type(then_val);
let else_ty = self.get_val_type(else_val);
assert_eq!(
then_ty, else_ty,
"Type of the select then value {} does not match the type of the else value {}",
then_ty, else_ty
);
let dst = self.create_val(then_ty);
self.push_inst(Inst::Select {
cond,
then_val,
else_val,
dst,
});
dst
}
fn iresize(&mut self, src: Value, dst_ty: IRType) -> Value {
let src_ty = self.get_val_type(src);
assert!(
src_ty.is_int(),
"Source value of iresize must be integer type"
);
assert!(
dst_ty.is_int(),
"Destination type of iresize must be integer type"
);
let dst = self.create_val(dst_ty);
self.push_inst(Inst::IResize { src, dst_ty, dst });
dst
}
fn fresize(&mut self, src: Value, dst_ty: IRType) -> Value {
let src_ty = self.get_val_type(src);
assert!(
src_ty.is_float(),
"Source value of fresize must be integer type"
);
assert!(
dst_ty.is_float(),
"Destination type of fresize must be integer type"
);
let dst = self.create_val(dst_ty);
self.push_inst(Inst::FResize { src, dst_ty, dst });
dst
}
fn itof(&mut self, src: Value) -> Value {
let src_ty = self.get_val_type(src);
let dst_ty = match src_ty {
IRType::I8 | IRType::I16 => {
panic!("Integer type smaller than 32-bit is not supported in itof")
}
IRType::I32 => IRType::F32,
IRType::I64 => IRType::F64,
_ => panic!("Source value of int_to_float must be integer type"),
};
let dst = self.create_val(dst_ty);
self.push_inst(Inst::IToF { src, dst_ty, dst });
dst
}
fn ftoi(&mut self, src: Value) -> Value {
let src_ty = self.get_val_type(src);
let dst_ty = match src_ty {
IRType::F32 => IRType::I32,
IRType::F64 => IRType::I64,
_ => panic!("Source value of float_to_int must be float type"),
};
let dst = self.create_val(dst_ty);
self.push_inst(Inst::FToI { src, dst_ty, dst });
dst
}
fn ptr_add(&mut self, ptr: Value, offset: Offset) -> Value {
let dst = self.create_val(IRType::Ptr);
self.push_inst(Inst::PtrAdd { ptr, offset, dst });
dst
}
fn ibop(&mut self, op: IntBinOp, lhs: Value, rhs: Value) -> Value {
let lhs_ty = self.get_val_type(lhs);
let rhs_ty = self.get_val_type(rhs);
assert_eq!(
lhs_ty, rhs_ty,
"Type of the binary op lhs {} does not match the type of the rhs {}",
lhs_ty, rhs_ty
);
assert!(
lhs_ty.is_int(),
"Type of the lhs is expected to be integer but got {}",
lhs_ty
);
assert!(
rhs_ty.is_int(),
"Type of the rhs is expected to be integer but got {}",
rhs_ty
);
let dst = self.create_val(lhs_ty);
self.push_inst(Inst::IBinOp { op, lhs, rhs, dst });
dst
}
fn fbop(&mut self, op: FloatBinOp, lhs: Value, rhs: Value) -> Value {
let lhs_ty = self.get_val_type(lhs);
let rhs_ty = self.get_val_type(rhs);
assert_eq!(
lhs_ty, rhs_ty,
"Type of the binary op lhs {} does not match the type of the rhs {}",
lhs_ty, rhs_ty
);
assert!(
lhs_ty.is_float(),
"Type of the lhs is expected to be float but got {}",
lhs_ty
);
assert!(
rhs_ty.is_float(),
"Type of the rhs is expected to be float but got {}",
rhs_ty
);
let dst = self.create_val(lhs_ty);
self.push_inst(Inst::FBinOp { op, lhs, rhs, dst });
dst
}
fn iuop(&mut self, op: IntUnaryOp, operand: Value) -> Value {
let operand_ty = self.get_val_type(operand);
assert!(
operand_ty.is_int(),
"Type of the unary op operand is expected to be integer but got {}",
operand_ty
);
let dst = self.create_val(operand_ty);
self.push_inst(Inst::IUnaryOp { op, operand, dst });
dst
}
fn fuop(&mut self, op: FloatUnaryOp, operand: Value) -> Value {
let operand_ty = self.get_val_type(operand);
assert!(
operand_ty.is_float(),
"Type of the unary op operand is expected to be float but got {}",
operand_ty
);
let dst = self.create_val(operand_ty);
self.push_inst(Inst::FUnaryOp { op, operand, dst });
dst
}
fn icmp(&mut self, cmp: IntCmp, lhs: Value, rhs: Value) -> Value {
let lhs_ty = self.get_val_type(lhs);
let rhs_ty = self.get_val_type(rhs);
assert_eq!(
lhs_ty, rhs_ty,
"Type of the int cmp lhs {} does not match the type of the rhs {}",
lhs_ty, rhs_ty
);
assert!(
lhs_ty.is_int(),
"Type of the lhs is expected to be integer but got {}",
lhs_ty
);
assert!(
rhs_ty.is_int(),
"Type of the rhs is expected to be integer but got {}",
rhs_ty
);
let dst = self.create_val(IRType::I8);
self.push_inst(Inst::ICmp { cmp, lhs, rhs, dst });
dst
}
fn fcmp(&mut self, cmp: FloatCmp, lhs: Value, rhs: Value) -> Value {
let lhs_ty = self.get_val_type(lhs);
let rhs_ty = self.get_val_type(rhs);
assert_eq!(
lhs_ty, rhs_ty,
"Type of the float cmp lhs {} does not match the type of the rhs {}",
lhs_ty, rhs_ty
);
assert!(
lhs_ty.is_float(),
"Type of the lhs is expected to be float but got {}",
lhs_ty
);
assert!(
rhs_ty.is_float(),
"Type of the rhs is expected to be float but got {}",
rhs_ty
);
let dst = self.create_val(IRType::I8);
self.push_inst(Inst::FCmp { cmp, lhs, rhs, dst });
dst
}
fn icmp_imm(&mut self, cmp: IntCmp, lhs: Value, rhs: i64) -> Value {
let lhs_ty = self.get_val_type(lhs);
assert!(
lhs_ty.is_int(),
"Type of the lhs is expected to be integer but got {}",
lhs_ty
);
let dst = self.create_val(IRType::I8);
self.push_inst(Inst::ICmpImm { cmp, lhs, rhs, dst });
dst
}
}