///|
pub fn Module::legalize(self : Self) -> Unit raise MIRError {
self.functions.values().each(f => f.legalize())
}
///|
pub fn Function::legalize(func : Function) -> Unit raise MIRError {
for bb in func.body {
bb.legalize()
}
}
///|
pub fn BasicBlock::legalize(self : BasicBlock) -> Unit raise MIRError {
let new_insts : Array[Instruction] = Array::new()
for inst in self.insts {
inst.legalize().each(new_inst => new_insts.push(new_inst))
}
self.insts = new_insts
}
///|
pub fn Instruction::legalize(
self : Instruction,
) -> Array[Instruction] raise MIRError {
let { bb, func, .. } = self
let builder = IRBuilder::new(func, bb)
match self.opcode {
IBinary(_) => self.legalize_ibinary(builder)
IUnary(_) => self.legalize_iunary(builder)
ICmp(_) => self.legalize_icmp(builder)
ILoad(_) => self.legalize_iload(builder)
IStore(_) => self.legalize_istore(builder)
IMove(_) => self.legalize_imove(builder)
Branch(_) => self.legalize_branch(builder)
FBinary(_) => self.legalize_fbinary(builder)
FUnary(_) => self.legalize_funary(builder)
FCmp(_) => self.legalize_fcmp(builder)
FLoad(_) => self.legalize_fload(builder)
FStore(_) => self.legalize_fstore(builder)
FMove(_) => self.legalize_fmove(builder)
FMoveI(_) => self.legalize_fmovei(builder)
IMoveF(_) => self.legalize_imovef(builder)
Call => [self]
Ret => [self]
Nop => [self]
LoadAddr => self.legalize_load_addr(builder)
Cast(_) => self.legalize_cast(builder)
Intrinsic(_) => raise LegalizeError("Unimplmented Intrinsic legalize Yet")
op => raise LegalizeError("Unimplmented \{op} Yet")
}
}
///|
fn Instruction::legalize_ibinary(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: IBinary(binop, bits), .. } else {
println(
"Compiler ICE: calling legalize_ibinary on non-IBinary instruction: \{self}",
)
panic()
}
// If bits is 8 or 16, we need to extend/promote to 32 bits
if bits == 8 || bits == 16 {
// For 8 and 16 bit operations, we need to:
// 1. Zero-extend or sign-extend operands to 32 bits
// 2. Perform the operation in 32 bits
// 3. Truncate back to the original size if needed
guard self is { defs: [dst_def], uses, .. } else {
return [self] // If not in expected form, return as-is
}
// Extend operands to 32 bits
let extended_uses : Array[Operand] = Array::new()
for use_op in uses {
match use_op {
IRegister(_) => {
let ext_reg = func.new_virtual_reg()
extended_uses.push(IRegister(ext_reg))
}
_ =>
// For immediates and other operand types, keep as-is
extended_uses.push(use_op)
}
}
// Create a 32-bit binary operation with extended operands
let temp_dst = func.new_virtual_reg()
let result_insts : Array[Instruction] = Array::new()
// Build extension instructions for register operands
for i, use_op in uses {
match use_op {
IRegister(r) =>
match extended_uses[i] {
IRegister(ext_reg) =>
result_insts.push(
builder.build_zext(
from_ty_size=bits,
to_ty_size=32,
dst=ext_reg,
src=r,
),
)
_ => ()
}
_ => ()
}
}
// Build the 32-bit binary operation
guard extended_uses.length() >= 2 else { return [self] }
let op1 = extended_uses[0]
let op2 = extended_uses[1]
match (op1, op2) {
(IRegister(r1), IRegister(r2)) =>
result_insts.push(
builder.build_ibinary(binop, 32, dst=temp_dst, src1=r1, src2=r2),
)
(IRegister(r1), Imm(i2)) =>
result_insts.push(
builder.build_ibinary_imm(binop, 32, dst=temp_dst, src1=r1, src2=i2),
)
_ => return [self] // Unsupported operand combination
}
// Truncate back to original size if destination is a register
match dst_def {
IRegister(dst) =>
result_insts.push(
builder.build_trunc(
from_ty_size=32,
to_ty_size=bits,
dst~,
src=temp_dst,
),
)
Mem(base, offset) =>
// If destination is memory, just store the 32-bit result with appropriate size
result_insts.push(
builder.build_storei(bits, src=temp_dst, base~, offset~),
)
_ => return [self]
}
return result_insts
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_ibinary(binop, bits, dst=v1, src1=v1, src2=v2),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), IRegister(r2)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_ibinary(binop, bits, dst=v1, src1=v1, src2=r2),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), Imm(i2)], .. } => {
let v1 = func.keeped_treg1()
if func.mod.arch_config.is_valid_imm(i2) {
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_ibinary_imm(binop, bits, dst=v1, src1=v1, src2=i2),
builder.build_storei(bits, src=v1, base~, offset~),
]
} else {
let v2 = func.new_virtual_reg()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_ibinary(binop, bits, dst=v1, src1=v1, src2=v2),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
}
{ defs: [Mem(base, offset)], uses: [IRegister(r1), Mem(b2, o2)], .. } => {
let v2 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_ibinary(binop, bits, dst=v2, src1=r1, src2=v2),
builder.build_storei(bits, src=v2, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(r1), IRegister(r2)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_ibinary(binop, bits, dst=vdst, src1=r1, src2=r2),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(r1), Imm(i2)], .. } => {
let vdst = func.keeped_treg1()
if func.mod.arch_config.is_valid_imm(i2) {
[
builder.build_ibinary_imm(binop, bits, dst=vdst, src1=r1, src2=i2),
builder.build_storei(bits, src=vdst, base~, offset~),
]
} else {
let v2 = func.new_virtual_reg()
[
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_ibinary(binop, bits, dst=vdst, src1=r1, src2=v2),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
}
{ defs: [Mem(base, offset)], uses: [Imm(i1), Mem(b2, o2)], .. } if binop.is_commutative() => {
let v = func.keeped_treg1()
if func.mod.arch_config.is_valid_imm(i1) {
[
builder.build_loadi(bits, dst=v, base=b2, offset=o2),
builder.build_ibinary_imm(binop, bits, dst=v, src1=v, src2=i1),
builder.build_storei(bits, src=v, base~, offset~),
]
} else {
let v2 = func.new_virtual_reg()
[
builder.build_loadi(bits, dst=v, base=b2, offset=o2),
builder.build_imove_imm(bits, dst=v2, src=i1),
builder.build_ibinary(binop, bits, dst=v, src1=v, src2=v2),
builder.build_storei(bits, src=v, base~, offset~),
]
}
}
{ defs: [Mem(base, offset)], uses: [Imm(i1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_imove_imm(bits, dst=v1, src=i1),
builder.build_ibinary(binop, bits, dst=v1, src1=v1, src2=v2),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(i1), IRegister(r2)], .. } if binop.is_commutative() => {
let v = func.keeped_treg1()
if func.mod.arch_config.is_valid_imm(i1) {
[
builder.build_ibinary_imm(binop, bits, dst=v, src1=r2, src2=i1),
builder.build_storei(bits, src=v, base~, offset~),
]
} else {
let v2 = func.new_virtual_reg()
[
builder.build_imove_imm(bits, dst=v2, src=i1),
builder.build_ibinary(binop, bits, dst=v, src1=r2, src2=v2),
builder.build_storei(bits, src=v, base~, offset~),
]
}
}
{ defs: [Mem(base, offset)], uses: [Imm(i1), IRegister(r2)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=v1, src=i1),
builder.build_ibinary(binop, bits, dst=v1, src1=v1, src2=r2),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(i1), Imm(i2)], .. } => {
let i = match binop {
Add => i1 + i2
Sub => i1 - i2
Mul => i1 * i2
Div => i1 / i2
Rem => i1 % i2
And => i1 & i2
Or => i1 | i2
Xor => i1 ^ i2
Shl => i1 << i2.to_int()
LShr =>
(i1.reinterpret_as_uint64() >> i2.to_int()).reinterpret_as_int64()
AShr => i1 >> i2.to_int()
}
let vdst = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=vdst, src=i),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [IRegister(rdst)], uses: [Mem(b1, o1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_ibinary(binop, bits, dst=rdst, src1=v1, src2=v2),
]
}
{ defs: [IRegister(rdst)], uses: [Mem(b1, o1), IRegister(r2)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_ibinary(binop, bits, dst=rdst, src1=v1, src2=r2),
]
}
{ defs: [IRegister(rdst)], uses: [Mem(b1, o1), Imm(i2)], .. } => {
let v1 = func.keeped_treg1()
if func.mod.arch_config.is_valid_imm(i2) {
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_ibinary_imm(binop, bits, dst=rdst, src1=v1, src2=i2),
]
} else {
let v2 = func.new_virtual_reg()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_ibinary(binop, bits, dst=rdst, src1=v1, src2=v2),
]
}
}
{ defs: [IRegister(rdst)], uses: [IRegister(r1), Mem(b2, o2)], .. } => {
let v2 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_ibinary(binop, bits, dst=rdst, src1=r1, src2=v2),
]
}
{ defs: [IRegister(_)], uses: [IRegister(_), IRegister(_)], .. } => [self]
{ defs: [IRegister(rdst)], uses: [IRegister(r1), Imm(i2)], .. } =>
// Check if immediate is valid for the target architecture
if func.mod.arch_config.is_valid_imm(i2) {
[self]
} else {
// Load large immediate into a register first
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=tmp_reg, src=i2),
builder.build_ibinary(binop, bits, dst=rdst, src1=r1, src2=tmp_reg),
]
}
{
opcode: IBinary(binop, bits),
defs: [IRegister(rdst)],
uses: [Imm(i), IRegister(r2)],
..,
} if binop.is_commutative() =>
// Check if immediate is valid for the target architecture
if func.mod.arch_config.is_valid_imm(i) {
[builder.build_ibinary_imm(binop, bits, dst=rdst, src1=r2, src2=i)]
} else {
// Load large immediate into a register first
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=tmp_reg, src=i),
builder.build_ibinary(binop, bits, dst=rdst, src1=r2, src2=tmp_reg),
]
}
{ defs: [IRegister(rdst)], uses: [Imm(i), IRegister(r2)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=v1, src=i),
builder.build_ibinary(binop, bits, dst=rdst, src1=v1, src2=r2),
]
}
_ => raise LegalizeError("Unhandled IBinary legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_iunary(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: IUnary(unop, bits), .. } else {
println(
"Compiler ICE: calling legalize_iunary on non-IUnary instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1)], .. } => {
let (v1, vdst) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_iunary(unop, bits, dst=vdst, src=v1),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(r1)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_iunary(unop, bits, dst=vdst, src=r1),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(i1)], .. } => {
let i = match unop {
Not => i1.lnot()
}
let vdst = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=vdst, src=i),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [IRegister(rdst)], uses: [Mem(b1, o1)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_iunary(unop, bits, dst=rdst, src=v1),
]
}
{ defs: [IRegister(_)], uses: [IRegister(_)], .. } => [self]
{ defs: [IRegister(rdst)], uses: [Imm(i1)], .. } => {
let i = match unop {
Not => i1.lnot()
}
let vdst = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=vdst, src=i),
builder.build_imove(bits, dst=rdst, src=vdst),
]
}
_ => raise LegalizeError("Unhandled IUnary legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_icmp(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: ICmp(_, _), .. } else {
println(
"Compiler ICE: calling legalize_icmp on non-ICmp instruction: \{self}",
)
panic()
}
match self {
{
opcode: ICmp(cmpop, bits),
defs: [Mem(base, offset)],
uses: [Mem(b1, o1), Mem(b2, o2)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
let vdst = v1 // Reuse v1 for the result
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_icmp(cmpop, bits, dst=vdst, src1=v1, src2=v2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [Mem(base, offset)],
uses: [Mem(b1, o1), IRegister(r2)],
..,
} => {
let v1 = func.keeped_treg1()
let vdst = v1 // Reuse v1 for the result
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_icmp(cmpop, bits, dst=vdst, src1=v1, src2=r2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [Mem(base, offset)],
uses: [Mem(b1, o1), Imm(i2)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
let vdst = v1 // Reuse v1 for the result
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_icmp(cmpop, bits, dst=vdst, src1=v1, src2=v2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [Mem(base, offset)],
uses: [IRegister(r1), Mem(b2, o2)],
..,
} => {
let v2 = func.keeped_treg1()
let vdst = v2 // Reuse v2 for the result
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_icmp(cmpop, bits, dst=vdst, src1=r1, src2=v2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [Mem(base, offset)],
uses: [IRegister(r1), IRegister(r2)],
..,
} => {
let vdst = func.keeped_treg1()
[
builder.build_icmp(cmpop, bits, dst=vdst, src1=r1, src2=r2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [Mem(base, offset)],
uses: [IRegister(r1), Imm(i2)],
..,
} => {
let (vdst, v2) = func.keeped_treg2()
[
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_icmp(cmpop, bits, dst=vdst, src1=r1, src2=v2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [IRegister(rdst)],
uses: [Mem(b1, o1), Mem(b2, o2)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_icmp(cmpop, bits, dst=rdst, src1=v1, src2=v2),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [IRegister(rdst)],
uses: [Mem(b1, o1), IRegister(r2)],
..,
} => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_icmp(cmpop, bits, dst=rdst, src1=v1, src2=r2),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [IRegister(rdst)],
uses: [Mem(b1, o1), Imm(i2)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_icmp(cmpop, bits, dst=rdst, src1=v1, src2=v2),
]
}
{
opcode: ICmp(cmpop, bits),
defs: [IRegister(rdst)],
uses: [IRegister(r1), Mem(b2, o2)],
..,
} => {
let v2 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_icmp(cmpop, bits, dst=rdst, src1=r1, src2=v2),
]
}
{
opcode: ICmp(_, _),
defs: [IRegister(_)],
uses: [IRegister(_), IRegister(_)],
..,
} => [self]
{
opcode: ICmp(cmpop, bits),
defs: [IRegister(rdst)],
uses: [IRegister(r1), Imm(i2)],
..,
} => {
let v2 = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_icmp(cmpop, bits, dst=rdst, src1=r1, src2=v2),
]
}
_ => raise LegalizeError("Unhandled ICmp legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_iload(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: ILoad(bits), .. } else {
println(
"Compiler ICE: calling legalize_iload on non-ILoad instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [IRegister(_)], uses: [Mem(_)], .. } as inst => [inst]
_ => raise LegalizeError("Unhandled ILoad legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_istore(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: IStore(bits), .. } else {
println(
"Compiler ICE: calling legalize_istore on non-IStore instruction: \{self}",
)
panic()
}
match self {
{ defs: [], uses: [Mem(base, offset), Mem(b1, o1)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [], uses: [Mem(_), IRegister(_)], .. } as inst => [inst]
_ => raise LegalizeError("Unhandled IStore legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_imove(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: IMove(bits), .. } else {
println(
"Compiler ICE: calling legalize_imove on non-IMove instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_storei(bits, src=v1, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(r1)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_imove(bits, dst=vdst, src=r1),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(i1)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=vdst, src=i1),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [IRegister(d)], uses: [IRegister(s)], .. } if d == s => []
{ defs: [IRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(_)], uses: [Imm(_)], .. } as inst => [inst]
_ => raise LegalizeError("Unhandled IMove legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_branch(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: Branch(bop, bits), .. } else {
println(
"Compiler ICE: calling legalize_branch on non-IBranch instruction: \{self}",
)
panic()
}
match self {
{
defs: [],
uses: [Mem(b1, o1), Mem(b2, o2), Label(true_label), Label(false_label)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_branch(
bop,
bits,
lhs=v1,
rhs=v2,
true_label~,
false_label~,
),
]
}
{
defs: [],
uses: [Mem(b1, o1), IRegister(r2), Label(true_label), Label(false_label)],
..,
} => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_branch(
bop,
bits,
lhs=v1,
rhs=r2,
true_label~,
false_label~,
),
]
}
{
defs: [],
uses: [Mem(b1, o1), Imm(v2), Label(true_label), Label(false_label)],
..,
} => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base=b1, offset=o1),
builder.build_branch_imm(
bop,
bits,
lhs=v1,
rhs=v2,
true_label~,
false_label~,
),
]
}
{
defs: [],
uses: [IRegister(r1), Mem(b2, o2), Label(true_label), Label(false_label)],
..,
} => {
let v2 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_branch(
bop,
bits,
lhs=r1,
rhs=v2,
true_label~,
false_label~,
),
]
}
{ defs: [], uses: [IRegister(_), IRegister(_), Label(_), Label(_)], .. } as inst =>
[inst]
{
defs: [],
uses: [IRegister(r1), Imm(i2), Label(true_label), Label(false_label)],
..,
} => {
let v2 = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_branch(
bop,
bits,
lhs=r1,
rhs=v2,
true_label~,
false_label~,
),
]
}
{
defs: [],
uses: [Imm(i1), Mem(b2, o2), Label(true_label), Label(false_label)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_loadi(bits, dst=v2, base=b2, offset=o2),
builder.build_imove_imm(bits, dst=v1, src=i1),
builder.build_branch(
bop,
bits,
lhs=v1,
rhs=v2,
true_label~,
false_label~,
),
]
}
{
defs: [],
uses: [Imm(i1), IRegister(r2), Label(true_label), Label(false_label)],
..,
} => {
let v1 = func.keeped_treg1()
[
builder.build_imove_imm(bits, dst=v1, src=i1),
builder.build_branch(
bop,
bits,
lhs=v1,
rhs=r2,
true_label~,
false_label~,
),
]
}
{
defs: [],
uses: [Imm(i1), Imm(i2), Label(true_label), Label(false_label)],
..,
} => {
let (v1, v2) = func.keeped_treg2()
[
builder.build_imove_imm(bits, dst=v1, src=i1),
builder.build_imove_imm(bits, dst=v2, src=i2),
builder.build_branch(
bop,
bits,
lhs=v1,
rhs=v2,
true_label~,
false_label~,
),
]
}
{ defs: [], uses: [Label(_)], .. } as inst => [inst]
_ => raise LegalizeError("Unhandled IBranch legalization case: \{self}")
}
}
//
// Note: fbinary is not support fimm operand, if it happens, raise error
///|
pub fn Instruction::legalize_fbinary(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FBinary(binop, bits), .. } else {
println(
"Compiler ICE: calling legalize_fbinary on non-FBinary instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_ftreg2()
let vdst = v1 // Reuse v1 for the result
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fbinary(binop, bits, dst=vdst, src1=v1, src2=v2),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), FRegister(r2)], .. } => {
let v1 = func.keeped_ftreg1()
let vdst = v1 // Reuse v1 for the result
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_fbinary(binop, bits, dst=vdst, src1=v1, src2=r2),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(r1), Mem(b2, o2)], .. } => {
let v2 = func.keeped_ftreg1()
let vdst = v2 // Reuse v2 for the result
[
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fbinary(binop, bits, dst=vdst, src1=r1, src2=v2),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(r1), FRegister(r2)], .. } => {
let vdst = func.keeped_ftreg1()
[
builder.build_fbinary(binop, bits, dst=vdst, src1=r1, src2=r2),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [FRegister(rdst)], uses: [Mem(b1, o1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_ftreg2()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fbinary(binop, bits, dst=rdst, src1=v1, src2=v2),
]
}
{ defs: [FRegister(rdst)], uses: [Mem(b1, o1), FRegister(r2)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_fbinary(binop, bits, dst=rdst, src1=v1, src2=r2),
]
}
{ defs: [FRegister(rdst)], uses: [FRegister(r1), Mem(b2, o2)], .. } => {
let v2 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fbinary(binop, bits, dst=rdst, src1=r1, src2=v2),
]
}
{ defs: [FRegister(_)], uses: [FRegister(_), FRegister(_)], .. } as inst =>
[inst]
_ => raise LegalizeError("Unhandled FBinary legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_funary(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FUnary(unop, bits), .. } else {
println(
"Compiler ICE: calling legalize_funary on non-FUnary instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1)], .. } => {
let (v1, vdst) = func.keeped_ftreg2()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_funary(unop, bits, dst=vdst, src=v1),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(r1)], .. } => {
let vdst = func.keeped_ftreg1()
[
builder.build_funary(unop, bits, dst=vdst, src=r1),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [FRegister(rdst)], uses: [Mem(b1, o1)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_funary(unop, bits, dst=rdst, src=v1),
]
}
{ defs: [FRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
_ => raise LegalizeError("Unhandled FUnary legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_fcmp(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FCmp(fcmpop, bits), .. } else {
println(
"Compiler ICE: calling legalize_fcmp on non-FCmp instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_ftreg2()
let vdst = func.keeped_treg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fcmp(fcmpop, bits, dst=vdst, src1=v1, src2=v2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1), FRegister(r2)], .. } => {
let v1 = func.keeped_ftreg1()
let vdst = func.keeped_treg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_fcmp(fcmpop, bits, dst=vdst, src1=v1, src2=r2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(r1), Mem(b2, o2)], .. } => {
let v2 = func.keeped_ftreg1()
let vdst = func.keeped_treg1()
[
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fcmp(fcmpop, bits, dst=vdst, src1=r1, src2=v2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(r1), FRegister(r2)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_fcmp(fcmpop, bits, dst=vdst, src1=r1, src2=r2),
builder.build_storei(32, src=vdst, base~, offset~),
]
}
{ defs: [IRegister(rdst)], uses: [Mem(b1, o1), Mem(b2, o2)], .. } => {
let (v1, v2) = func.keeped_ftreg2()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fcmp(fcmpop, bits, dst=rdst, src1=v1, src2=v2),
]
}
{ defs: [IRegister(rdst)], uses: [Mem(b1, o1), FRegister(r2)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_fcmp(fcmpop, bits, dst=rdst, src1=v1, src2=r2),
]
}
{ defs: [IRegister(rdst)], uses: [FRegister(r1), Mem(b2, o2)], .. } => {
let v2 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v2, base=b2, offset=o2),
builder.build_fcmp(fcmpop, bits, dst=rdst, src1=r1, src2=v2),
]
}
{ defs: [IRegister(_)], uses: [FRegister(_), FRegister(_)], .. } as inst =>
[inst]
_ => raise LegalizeError("Unhandled FCmp legalization case: \{self}")
}
}
//FLoad(_) => self.legalize_fload(builder)
//FStore(_) => self.legalize_fstore(builder)
//FMove(_) => self.legalize_fmove(builder)
//FMoveI(_) => self.legalize_fmovei(builder)
//IMoveF(_) => self.legalize_imovef(builder)
///|
pub fn Instruction::legalize_fload(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FLoad(bits), .. } else {
println(
"Compiler ICE: calling legalize_fload on non-FLoad instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_storef(bits, src=v1, base~, offset~),
]
}
{ defs: [FRegister(_)], uses: [Mem(_)], .. } as inst => [inst]
_ => raise LegalizeError("Unhandled FLoad legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_fstore(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FStore(bits), .. } else {
println(
"Compiler ICE: calling legalize_fstore on non-FStore instruction: \{self}",
)
panic()
}
match self {
{ defs: [], uses: [Mem(_, _), FRegister(_)], .. } as inst => [inst]
{ defs: [], uses: [Mem(base, offset), FImm(imm_val)], .. } => {
let tmp_reg = func.keeped_ftreg1()
[
builder.build_fmove_imm(bits, dst=tmp_reg, src=imm_val),
builder.build_storef(bits, src=tmp_reg, base~, offset~),
]
}
{ defs: [], uses: [Mem(base, offset), Mem(b1, o1)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_storef(bits, src=v1, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled FStore legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_fmove(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FMove(bits), .. } else {
println(
"Compiler ICE: calling legalize_fmove on non-FMove instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [Mem(b1, o1)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base=b1, offset=o1),
builder.build_storef(bits, src=v1, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(r1)], .. } => {
let vdst = func.keeped_ftreg1()
[
builder.build_fmove(bits, dst=vdst, src=r1),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [FRegister(d)], uses: [FRegister(s)], .. } if d == s => []
{ defs: [FRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
{ defs: [FRegister(rdst)], uses: [FImm(imm_val)], .. } =>
// Handle immediate value to floating point register move
[builder.build_fmove_imm(bits, dst=rdst, src=imm_val)]
{ defs: [FRegister(rdst)], uses: [Mem(base, offset)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base~, offset~),
builder.build_fmove(bits, dst=rdst, src=v1),
]
}
_ => raise LegalizeError("Unhandled FMove legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_fmovei(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: FMoveI(bits), .. } else {
println(
"Compiler ICE: calling legalize_fmovei on non-FMoveI instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [IRegister(r1)], .. } => {
let v1 = func.keeped_treg1()
let vdst = func.keeped_ftreg1()
[
builder.build_imove(bits, dst=v1, src=r1),
builder.build_fmove_from_ireg(bits, dst=vdst, src=v1),
builder.build_storef(bits, src=vdst, base~, offset~),
]
}
{ defs: [FRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [FRegister(rdst)], uses: [Mem(base, offset)], .. } => {
let v1 = func.keeped_treg1()
[
builder.build_loadi(bits, dst=v1, base~, offset~),
builder.build_fmove_from_ireg(bits, dst=rdst, src=v1),
]
}
_ => raise LegalizeError("Unhandled FMoveI legalization case: \{self}")
}
}
///|
/// imovef means move from freg to ireg
pub fn Instruction::legalize_imovef(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: IMoveF(bits), .. } else {
println(
"Compiler ICE: calling legalize_imovef on non-IMoveF instruction: \{self}",
)
panic()
}
match self {
{ defs: [Mem(base, offset)], uses: [FRegister(r1)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_fmove_to_ireg(bits, dst=vdst, src=r1),
builder.build_storei(bits, src=vdst, base~, offset~),
]
}
{ defs: [IRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(rdst)], uses: [Mem(base, offset)], .. } => {
let v1 = func.keeped_ftreg1()
[
builder.build_loadf(bits, dst=v1, base~, offset~),
builder.build_fmove_to_ireg(bits, dst=rdst, src=v1),
]
}
_ => raise LegalizeError("Unhandled IMoveF legalization case: \{self}")
}
}
///|
///loadaddr means load address of a variable (in memory) into a register
///def must be IRegister, use must be label
pub fn Instruction::legalize_load_addr(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: LoadAddr, .. } else {
println(
"Compiler ICE: calling legalize_loadaddr on non-LoadAddr instruction: \{self}",
)
panic()
}
match self {
{ defs: [IRegister(_)], uses: [Label(_)], .. } => [self]
{ defs: [Mem(base, offset)], uses: [Label(label)], .. } => {
let vdst = func.keeped_treg1()
[
builder.build_load_addr(vdst, label),
builder.build_storei(64, src=vdst, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled LoadAddr legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast(
self : Instruction,
builder : IRBuilder,
) -> Array[Instruction] raise MIRError {
let { func, .. } = builder
guard self is { opcode: Cast(cast_op), .. } else {
println(
"Compiler ICE: calling legalize_cast on non-Cast instruction: \{self}",
)
panic()
}
match cast_op {
Trunc(_) => self.legalize_cast_trunc(builder, func, cast_op)
ZExt(_) => self.legalize_cast_zext(builder, func, cast_op)
SExt(_) => self.legalize_cast_sext(builder, func, cast_op)
FPTrunc(_) => self.legalize_cast_fptrunc(builder, func, cast_op)
FPExt(_) => self.legalize_cast_fpext(builder, func, cast_op)
FPToSI(_) => self.legalize_cast_fp_to_si(builder, func, cast_op)
FPToUI(_) => self.legalize_cast_fp_to_ui(builder, func, cast_op)
SIToFP(_) => self.legalize_cast_si_to_fp(builder, func, cast_op)
UIToFP(_) => self.legalize_cast_ui_to_fp(builder, func, cast_op)
}
}
///|
pub fn Instruction::legalize_cast_fp_to_si(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is FPToSI(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_fp_to_si on non-FPToSI cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [IRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(dst)], uses: [FImm(imm_val)], .. } => {
let src = func.keeped_ftreg1()
[
builder.build_fmove_imm(from_ty_size, dst=src, src=imm_val),
builder.build_fp_to_si(from_ty_size~, to_ty_size~, dst~, src~),
]
}
{ defs: [IRegister(dst)], uses: [Mem(base, offset)], .. } => {
let src = func.keeped_ftreg1()
[
builder.build_loadf(from_ty_size, dst=src, base~, offset~),
builder.build_fp_to_si(from_ty_size~, to_ty_size~, dst~, src~),
]
}
_ => raise LegalizeError("Unhandled FPToSI legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_fp_to_ui(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is FPToUI(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_fp_to_ui on non-FPToUI cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [IRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(dst)], uses: [FImm(imm_val)], .. } => {
let src = func.keeped_ftreg1()
[
builder.build_fmove_imm(from_ty_size, dst=src, src=imm_val),
builder.build_fp_to_ui(from_ty_size~, to_ty_size~, dst~, src~),
]
}
{ defs: [IRegister(dst)], uses: [Mem(base, offset)], .. } => {
let src = func.keeped_ftreg1()
[
builder.build_loadf(from_ty_size, dst=src, base~, offset~),
builder.build_fp_to_ui(from_ty_size~, to_ty_size~, dst~, src~),
]
}
_ => raise LegalizeError("Unhandled FPToUI legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_si_to_fp(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is SIToFP(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_si_to_fp on non-SIToFP cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [FRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [FRegister(dst)], uses: [Imm(imm_val)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_si_to_fp(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [FRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_loadi(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_si_to_fp(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
_ => raise LegalizeError("Unhandled SIToFP legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_ui_to_fp(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is UIToFP(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_ui_to_fp on non-UIToFP cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [FRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [FRegister(dst)], uses: [Imm(imm_val)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_ui_to_fp(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [FRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_loadi(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_ui_to_fp(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
_ => raise LegalizeError("Unhandled UIToFP legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_trunc(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is Trunc(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_trunc on non-Trunc cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [IRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(dst)], uses: [Imm(imm_val)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_trunc(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [IRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_loadi(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_trunc(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(src)], .. } => {
let dst_reg = func.keeped_treg1()
[
builder.build_trunc(from_ty_size~, to_ty_size~, dst=dst_reg, src~),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(imm_val)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_treg2()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_trunc(
from_ty_size~,
to_ty_size~,
dst=dst_reg,
src=tmp_reg,
),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(src_base, src_offset)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_treg2()
[
builder.build_loadi(
from_ty_size,
dst=tmp_reg,
base=src_base,
offset=src_offset,
),
builder.build_trunc(
from_ty_size~,
to_ty_size~,
dst=dst_reg,
src=tmp_reg,
),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled Trunc legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_zext(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is ZExt(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_zext on non-ZExt cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [IRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(dst)], uses: [Imm(imm_val)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_zext(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [IRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_loadi(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_zext(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(src)], .. } => {
let dst_reg = func.keeped_treg1()
[
builder.build_zext(from_ty_size~, to_ty_size~, dst=dst_reg, src~),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(imm_val)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_treg2()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_zext(from_ty_size~, to_ty_size~, dst=dst_reg, src=tmp_reg),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(src_base, src_offset)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_treg2()
[
builder.build_loadi(
from_ty_size,
dst=tmp_reg,
base=src_base,
offset=src_offset,
),
builder.build_zext(from_ty_size~, to_ty_size~, dst=dst_reg, src=tmp_reg),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled ZExt legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_sext(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is SExt(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_sext on non-SExt cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [IRegister(_)], uses: [IRegister(_)], .. } as inst => [inst]
{ defs: [IRegister(dst)], uses: [Imm(imm_val)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_sext(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [IRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_treg1()
[
builder.build_loadi(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_sext(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [Mem(base, offset)], uses: [IRegister(src)], .. } => {
let dst_reg = func.keeped_treg1()
[
builder.build_sext(from_ty_size~, to_ty_size~, dst=dst_reg, src~),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Imm(imm_val)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_treg2()
[
builder.build_imove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_sext(from_ty_size~, to_ty_size~, dst=dst_reg, src=tmp_reg),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(src_base, src_offset)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_treg2()
[
builder.build_loadi(
from_ty_size,
dst=tmp_reg,
base=src_base,
offset=src_offset,
),
builder.build_sext(from_ty_size~, to_ty_size~, dst=dst_reg, src=tmp_reg),
builder.build_storei(to_ty_size, src=dst_reg, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled SExt legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_fptrunc(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is FPTrunc(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_fptrunc on non-FPTrunc cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [FRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
{ defs: [FRegister(dst)], uses: [FImm(imm_val)], .. } => {
let tmp_reg = func.keeped_ftreg1()
[
builder.build_fmove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_fptrunc(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [FRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_ftreg1()
[
builder.build_loadf(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_fptrunc(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(src)], .. } => {
let dst_reg = func.keeped_ftreg1()
[
builder.build_fptrunc(from_ty_size~, to_ty_size~, dst=dst_reg, src~),
builder.build_storef(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FImm(imm_val)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_ftreg2()
[
builder.build_fmove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_fptrunc(
from_ty_size~,
to_ty_size~,
dst=dst_reg,
src=tmp_reg,
),
builder.build_storef(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(src_base, src_offset)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_ftreg2()
[
builder.build_loadf(
from_ty_size,
dst=tmp_reg,
base=src_base,
offset=src_offset,
),
builder.build_fptrunc(
from_ty_size~,
to_ty_size~,
dst=dst_reg,
src=tmp_reg,
),
builder.build_storef(to_ty_size, src=dst_reg, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled FPTrunc legalization case: \{self}")
}
}
///|
pub fn Instruction::legalize_cast_fpext(
self : Instruction,
builder : IRBuilder,
func : Function,
cast_op : CastOpCode,
) -> Array[Instruction] raise MIRError {
guard cast_op is FPExt(from_ty_size, to_ty_size) else {
println(
"Compiler ICE: calling legalize_cast_fpext on non-FPExt cast operation: \{cast_op}",
)
panic()
}
match self {
{ defs: [FRegister(_)], uses: [FRegister(_)], .. } as inst => [inst]
{ defs: [FRegister(dst)], uses: [FImm(imm_val)], .. } => {
let tmp_reg = func.keeped_ftreg1()
[
builder.build_fmove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_fpext(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [FRegister(dst)], uses: [Mem(base, offset)], .. } => {
let tmp_reg = func.keeped_ftreg1()
[
builder.build_loadf(from_ty_size, dst=tmp_reg, base~, offset~),
builder.build_fpext(from_ty_size~, to_ty_size~, dst~, src=tmp_reg),
]
}
{ defs: [Mem(base, offset)], uses: [FRegister(src)], .. } => {
let dst_reg = func.keeped_ftreg1()
[
builder.build_fpext(from_ty_size~, to_ty_size~, dst=dst_reg, src~),
builder.build_storef(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [FImm(imm_val)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_ftreg2()
[
builder.build_fmove_imm(from_ty_size, dst=tmp_reg, src=imm_val),
builder.build_fpext(
from_ty_size~,
to_ty_size~,
dst=dst_reg,
src=tmp_reg,
),
builder.build_storef(to_ty_size, src=dst_reg, base~, offset~),
]
}
{ defs: [Mem(base, offset)], uses: [Mem(src_base, src_offset)], .. } => {
let (tmp_reg, dst_reg) = func.keeped_ftreg2()
[
builder.build_loadf(
from_ty_size,
dst=tmp_reg,
base=src_base,
offset=src_offset,
),
builder.build_fpext(
from_ty_size~,
to_ty_size~,
dst=dst_reg,
src=tmp_reg,
),
builder.build_storef(to_ty_size, src=dst_reg, base~, offset~),
]
}
_ => raise LegalizeError("Unhandled FPExt legalization case: \{self}")
}
}