///|
pub struct IRBuilder {
func : Function
bb : BasicBlock
}
///|
fn check_bits(bits : Int, loc : SourceLoc) -> Unit raise MIRError {
guard bits is (8 | 16 | 32 | 64) else {
raise InValidBitWidthError("Invalid bit width: \{bits}, loc: \{loc}")
}
}
///|
pub fn IRBuilder::new(func : Function, bb : BasicBlock) -> IRBuilder {
IRBuilder::{ func, bb }
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_loadi(
self : Self,
bits : Int,
dst~ : IRegister,
base~ : IRegister,
offset~ : Int64,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src = Operand::Mem(base, offset)
Instruction::new(ILoad(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_loadf(
self : Self,
bits : Int,
dst~ : FRegister,
base~ : IRegister,
offset~ : Int64,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src = Operand::Mem(base, offset)
Instruction::new(FLoad(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_storei(
self : Self,
bits : Int,
src~ : IRegister,
base~ : IRegister,
offset~ : Int64,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let src = Operand::IRegister(src)
let dst = Operand::Mem(base, offset)
Instruction::new(IStore(bits), [], [dst, src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_storef(
self : Self,
bits : Int,
src~ : FRegister,
base~ : IRegister,
offset~ : Int64,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let src = Operand::FRegister(src)
let dst = Operand::Mem(base, offset)
Instruction::new(FStore(bits), [], [dst, src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_ibinary(
self : Self,
binop : IBinaryOpCode,
bits : Int,
dst~ : IRegister,
src1~ : IRegister,
src2~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src1 = Operand::IRegister(src1)
let src2 = Operand::IRegister(src2)
Instruction::new(IBinary(binop, bits), [dst], [src1, src2], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_ibinary_imm(
self : Self,
binop : IBinaryOpCode,
bits : Int,
dst~ : IRegister,
src1~ : IRegister,
src2~ : Int64,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src1 = Operand::IRegister(src1)
let src2 = Operand::Imm(src2)
Instruction::new(IBinary(binop, bits), [dst], [src1, src2], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fbinary(
self : Self,
binop : FBinaryOpCode,
bits : Int,
dst~ : FRegister,
src1~ : FRegister,
src2~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src1 = Operand::FRegister(src1)
let src2 = Operand::FRegister(src2)
Instruction::new(FBinary(binop, bits), [dst], [src1, src2], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_funary(
self : Self,
unop : FUnaryOpCode,
bits : Int,
dst~ : FRegister,
src~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(FUnary(unop, bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fneg(
self : Self,
bits : Int,
dst~ : FRegister,
src~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(FUnary(FNeg, bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_icmp(
self : Self,
cmpop : ICmpOpCode,
bits : Int,
dst~ : IRegister,
src1~ : IRegister,
src2~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src1 = Operand::IRegister(src1)
let src2 = Operand::IRegister(src2)
Instruction::new(ICmp(cmpop, bits), [dst], [src1, src2], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fcmp(
self : Self,
cmpop : FCmpOpCode,
bits : Int,
dst~ : IRegister,
src1~ : FRegister,
src2~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src1 = Operand::FRegister(src1)
let src2 = Operand::FRegister(src2)
Instruction::new(FCmp(cmpop, bits), [dst], [src1, src2], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_iunary(
self : Self,
unop : IUnaryOpCode,
bits : Int,
dst~ : IRegister,
src~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(IUnary(unop, bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_imove(
self : Self,
bits : Int,
dst~ : IRegister,
src~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(IMove(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_imove_imm(
self : Self,
bits : Int,
dst~ : IRegister,
src~ : Int64,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src = Operand::Imm(src)
Instruction::new(IMove(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fmove(
self : Self,
bits : Int,
dst~ : FRegister,
src~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(FMove(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fmove_imm(
self : Self,
bits : Int,
dst~ : FRegister,
src~ : Double,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src = Operand::FImm(src)
Instruction::new(FMove(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fmove_from_ireg(
self : Self,
bits : Int,
dst~ : FRegister,
src~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::FRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(FMoveI(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fmove_to_ireg(
self : Self,
bits : Int,
dst~ : IRegister,
src~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
check_bits(bits, loc)
let dst = Operand::IRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(IMoveF(bits), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_trunc(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : IRegister,
src~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
guard from_ty_size > to_ty_size else {
raise InValidBitWidthError(
"from_size must be greater than to_size: \{from_ty_size} <= \{to_ty_size}, loc: \{loc}",
)
}
let dst = Operand::IRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(Cast(Trunc(from_ty_size, to_ty_size)), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_zext(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : IRegister,
src~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
guard from_ty_size < to_ty_size else {
raise InValidBitWidthError(
"from_size must be less than to_size: \{from_ty_size} >= \{to_ty_size}, loc: \{loc}",
)
}
let dst = Operand::IRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(Cast(ZExt(from_ty_size, to_ty_size)), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_sext(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : IRegister,
src~ : IRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
guard from_ty_size < to_ty_size else {
raise InValidBitWidthError(
"from_size must be less than to_size: \{from_ty_size} >= \{to_ty_size}, loc: \{loc}",
)
}
let dst = Operand::IRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(Cast(SExt(from_ty_size, to_ty_size)), [dst], [src], self.bb)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fptrunc(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : FRegister,
src~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
guard from_ty_size > to_ty_size else {
raise InValidBitWidthError(
"from_size must be greater than to_size: \{from_ty_size} <= \{to_ty_size}, loc: \{loc}",
)
}
let dst = Operand::FRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(
Cast(FPTrunc(from_ty_size, to_ty_size)),
[dst],
[src],
self.bb,
)
}
///|
#callsite(autofill(loc))
pub fn IRBuilder::build_fpext(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : FRegister,
src~ : FRegister,
loc~ : SourceLoc,
) -> Instruction raise MIRError {
guard from_ty_size < to_ty_size else {
raise InValidBitWidthError(
"from_size must be less than to_size: \{from_ty_size} >= \{to_ty_size}, loc: \{loc}",
)
}
let dst = Operand::FRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(Cast(FPExt(from_ty_size, to_ty_size)), [dst], [src], self.bb)
}
///|
pub fn IRBuilder::build_fp_to_si(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : IRegister,
src~ : FRegister,
) -> Instruction {
let dst = Operand::IRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(
Cast(FPToSI(from_ty_size, to_ty_size)),
[dst],
[src],
self.bb,
)
}
///|
pub fn IRBuilder::build_fp_to_ui(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : IRegister,
src~ : FRegister,
) -> Instruction {
let dst = Operand::IRegister(dst)
let src = Operand::FRegister(src)
Instruction::new(
Cast(FPToUI(from_ty_size, to_ty_size)),
[dst],
[src],
self.bb,
)
}
///|
pub fn IRBuilder::build_si_to_fp(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : FRegister,
src~ : IRegister,
) -> Instruction {
let dst = Operand::FRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(
Cast(SIToFP(from_ty_size, to_ty_size)),
[dst],
[src],
self.bb,
)
}
///|
pub fn IRBuilder::build_ui_to_fp(
self : Self,
from_ty_size~ : Int,
to_ty_size~ : Int,
dst~ : FRegister,
src~ : IRegister,
) -> Instruction {
let dst = Operand::FRegister(dst)
let src = Operand::IRegister(src)
Instruction::new(
Cast(UIToFP(from_ty_size, to_ty_size)),
[dst],
[src],
self.bb,
)
}
///|
pub fn IRBuilder::build_load_addr(
self : Self,
dst : IRegister,
label : String,
) -> Instruction {
let dst = Operand::IRegister(dst)
let src = Operand::Label(label)
Instruction::new(LoadAddr, [dst], [src], self.bb)
}
///|
pub fn IRBuilder::build_ret(self : Self) -> Instruction {
Instruction::new(Ret, [], [], self.bb)
}
///|
pub fn IRBuilder::build_branch(
self : Self,
opcode : BranchOpCode,
bits : Int,
lhs~ : IRegister,
rhs~ : IRegister,
true_label~ : String,
false_label~ : String,
) -> Instruction {
let lhs = Operand::IRegister(lhs)
let rhs = Operand::IRegister(rhs)
let true_label = Operand::Label(true_label)
let false_label = Operand::Label(false_label)
Instruction::new(
Branch(opcode, bits),
[],
[lhs, rhs, true_label, false_label],
self.bb,
)
}
///|
pub fn IRBuilder::build_branch_imm(
self : Self,
opcode : BranchOpCode,
bits : Int,
lhs~ : IRegister,
rhs~ : Int64,
true_label~ : String,
false_label~ : String,
) -> Instruction {
let lhs = Operand::IRegister(lhs)
let rhs = Operand::Imm(rhs)
let true_label = Operand::Label(true_label)
let false_label = Operand::Label(false_label)
Instruction::new(
Branch(opcode, bits),
[],
[lhs, rhs, true_label, false_label],
self.bb,
)
}
///|
pub fn IRBuilder::build_jmp(self : Self, target_label~ : String) -> Instruction {
let target_label = Operand::Label(target_label)
Instruction::new(Branch(Jmp, 64), [], [target_label], self.bb)
}
///|
pub fn IRBuilder::build_call(self : Self, func_name : String) -> Instruction {
let func_name = Operand::Label(func_name)
Instruction::new(Call, [], [func_name], self.bb)
}