From ef11ae9d96eaf2e3b050749337039d5c35adadd4 Mon Sep 17 00:00:00 2001 From: Hydrostic Date: Fri, 15 May 2026 11:04:05 +0800 Subject: [PATCH] feat(backend): Support cmp/label/bc/br ir instr --- src/backend/arm_instr.rs | 79 +++++++++++-- src/backend/generator.rs | 189 ++++++++++++++++++++---------- src/backend/mod.rs | 4 + src/backend/register_allocator.rs | 17 ++- 4 files changed, 217 insertions(+), 72 deletions(-) diff --git a/src/backend/arm_instr.rs b/src/backend/arm_instr.rs index ccf7fb3..60f421c 100644 --- a/src/backend/arm_instr.rs +++ b/src/backend/arm_instr.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, ops::Add}; -use crate::backend::register_allocator::{REG_FP, REG_LR, REG_PC, REG_R0, REG_R1, REG_R2, REG_R3, REG_R12, REG_SP, Register}; +use crate::{backend::register_allocator::{REG_FP, REG_LR, REG_PC, REG_R0, REG_R1, REG_R2, REG_R3, REG_R12, REG_SP, Register}, ir::types::CmpOp as IRCmpOp}; pub enum ARMInstr{ Move(MoveInstr), Load(LoadInstr), @@ -10,11 +10,14 @@ pub enum ARMInstr{ SDiv(SDivInstr), Add(AddInstr), Sub(SubInstr), + Rsb(RsbInstr), Cmp(CmpInstr), Push(PushInstr), Pop(PopInstr), FunctionHead(String, usize), Bl(BlInstr), + B(BInstr), + Label(String), } impl Display for ARMInstr { @@ -28,11 +31,14 @@ impl Display for ARMInstr { ARMInstr::SDiv(instr) => write!(f, "{}", instr), ARMInstr::Add(instr) => write!(f, "{}", instr), ARMInstr::Sub(instr) => write!(f, "{}", instr), + ARMInstr::Rsb(instr) => write!(f, "{}", instr), ARMInstr::Cmp(instr) => write!(f, "{}", instr), ARMInstr::Push(instr) => write!(f, "{}", instr), ARMInstr::Pop(instr) => write!(f, "{}", instr), ARMInstr::Bl(instr) => write!(f, "{}", instr), + ARMInstr::B(instr) => write!(f, "{}", instr), ARMInstr::FunctionHead(name, align_size) => write!(f, ".align {}\n.global {}\n.type {}, %function\n{}:", align_size, name, name, name), + ARMInstr::Label(name) => write!(f, "{}:", name), } } } @@ -56,6 +62,18 @@ pub enum ConditionCode { Gt, Ge, } +impl From for ConditionCode { + fn from(cmp_op: IRCmpOp) -> Self { + match cmp_op { + IRCmpOp::Eq => ConditionCode::Eq, + IRCmpOp::Ne => ConditionCode::Ne, + IRCmpOp::Lt => ConditionCode::Lt, + IRCmpOp::Le => ConditionCode::Le, + IRCmpOp::Gt => ConditionCode::Gt, + IRCmpOp::Ge => ConditionCode::Ge, + } + } +} impl Display for ConditionCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let code_str = match self { @@ -89,6 +107,9 @@ impl MoveInstr { pub fn new_uncond(dest: Register, src: RegisterOrImm) -> ARMInstr { ARMInstr::Move(MoveInstr(None, dest, src)) } + pub fn new_cond(condition: ConditionCode, dest: Register, src: RegisterOrImm) -> ARMInstr { + ARMInstr::Move(MoveInstr(Some(condition), dest, src)) + } pub fn new_sp_to_fp() -> ARMInstr { ARMInstr::Move(MoveInstr(None, REG_FP, RegisterOrImm::Reg(REG_SP))) } @@ -205,20 +226,37 @@ impl SubInstr { ARMInstr::Sub(SubInstr(REG_SP, REG_SP, RegisterOrImm::Imm(offset))) } } + impl Display for SubInstr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let SubInstr(dest, left, right) = self; write!(f, "sub {}, {}, {}", dest, left, right) } } -pub struct CmpInstr(Register, Register); +pub struct RsbInstr(Register, Register, RegisterOrImm); +impl RsbInstr { + pub fn new(dest: Register, left: Register, right: RegisterOrImm) -> ARMInstr { + ARMInstr::Rsb(RsbInstr(dest, left, right)) + } +} +impl Display for RsbInstr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let RsbInstr(dest, left, right) = self; + write!(f, "rsb {}, {}, {}", dest, left, right) + } +} +pub struct CmpInstr(Register, RegisterOrImm); impl Display for CmpInstr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let CmpInstr(left, right) = self; write!(f, "cmp {}, {}", left, right) } } - +impl CmpInstr { + pub fn new(left: Register, right: RegisterOrImm) -> ARMInstr { + ARMInstr::Cmp(CmpInstr(left, right)) + } +} pub struct PushInstr(Vec); impl PushInstr { pub fn new_push_fp_lr() -> ARMInstr { @@ -272,16 +310,41 @@ impl Display for PopInstr { } } -pub struct BlInstr(String); +pub struct BlInstr(Option, String); impl Display for BlInstr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let BlInstr(func_name) = self; - write!(f, "bl {}", func_name) + match &self.0 { + Some(condition) => write!(f, "bl{} {}", condition, self.1), + None => write!(f, "bl {}", self.1), + } } } impl BlInstr { - pub fn new(func_name: String) -> ARMInstr { - ARMInstr::Bl(BlInstr(func_name)) + pub fn new(label_name: String) -> ARMInstr { + ARMInstr::Bl(BlInstr(None, label_name)) + } + + pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr { + ARMInstr::Bl(BlInstr(Some(condition), label_name)) + } +} +pub struct BInstr(Option, String); +impl Display for BInstr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.0 { + Some(condition) => write!(f, "b{} {}", condition, self.1), + None => write!(f, "b {}", self.1), + } + } +} + +impl BInstr { + pub fn new(label_name: String) -> ARMInstr { + ARMInstr::B(BInstr(None, label_name)) + } + + pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr { + ARMInstr::B(BInstr(Some(condition), label_name)) } } \ No newline at end of file diff --git a/src/backend/generator.rs b/src/backend/generator.rs index 07ec23f..8dba967 100644 --- a/src/backend/generator.rs +++ b/src/backend/generator.rs @@ -1,7 +1,10 @@ use std::collections::BTreeMap; -use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BlInstr, LoadInstr, LoadPseudoInstr, MoveInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_R0, REG_R1, REG_R2, REG_R3, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableType}}; +use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, LoadPseudoInstr, MoveInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_R0, REG_R1, REG_R2, REG_R3, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}}; use crate::ir::types::BinaryOp as IRBinaryOp; +use crate::ir::types::CmpOp as IRCmpOp; +use crate::ir::types::UnaryOp as IRUnaryOp; + pub const ARM_STACK_ALIGNMENT: usize = 8; pub struct Generator { instrs: Vec, @@ -11,6 +14,49 @@ pub struct Generator { } const DEFAULT_VAR_ALIGN: usize = 4; + +fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap, instrs: &mut Vec) -> RegisterAlloc { + match variable.var_type { + VariableType::Global => { + let var_alloc = reg_allocator.alloc(variable).expect("Ran out of registers"); + let var_reg = var_alloc.reg; + // if !var_alloc.is_reused { + let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers"); + instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index))); + instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None)); + // } + var_alloc + }, + VariableType::ParamTemp => { + todo!() + }, + _ => { + let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); + let var_alloc = reg_allocator.alloc(variable).expect("Ran out of registers"); + // if !var_alloc.is_reused { + instrs.push(LoadInstr::new_stack(var_alloc.reg, *stack_offset as i32)); + // } + var_alloc + } + } +} + +fn save_variable(variable: Variable, reg: Register, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap, instrs: &mut Vec) { + match variable.var_type { + VariableType::Global => { + let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers"); + instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index))); + instrs.push(StoreInstr::new(reg, address_alloc.reg, None)); + }, + VariableType::ParamTemp => { + todo!() + }, + _ => { + let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared"); + instrs.push(StoreInstr::new_stack(reg, *stack_offset as i32)); + } + } +} impl Generator { pub fn new() -> Self { Self { @@ -59,10 +105,10 @@ impl Generator { self.instrs.push(ARMInstr::FunctionHead(func.name.clone(), 4)); // Assuming 4-byte alignment for simplicity self.instrs.push(PushInstr::new_push_fp_lr()); self.instrs.push(MoveInstr::new_sp_to_fp()); - self.emit_func(body); + self.emit_func(&func.name, body); } - fn emit_func(&mut self, instrs: Vec) { + fn emit_func(&mut self, func_name: &str, instrs: Vec) { let mut encounter_entry = false; let mut stack_size_needed = 0; let mut var_index_to_stack_offset = BTreeMap::new(); @@ -73,13 +119,8 @@ impl Generator { if let Some(v) = v { let ret_alloc = self.register_allocator.alloc_reg(REG_R0).expect("Ran out of registers"); let ret_reg = ret_alloc.reg; - let v_alloc = self.register_allocator.alloc(v).expect("Ran out of registers"); - let v_reg = v_alloc.reg; - if !v_alloc.is_reused { - let v_stack_offset = var_index_to_stack_offset.get(&v.index).expect("Variable not declared"); - self.instrs.push(LoadInstr::new_stack(v_reg, *v_stack_offset as i32)); - } - self.instrs.push(MoveInstr::new_uncond(ret_reg, RegisterOrImm::Reg(v_reg))); + let v_alloc = load_variable(v, &mut self.register_allocator, &var_index_to_stack_offset, &mut self.instrs); + self.instrs.push(MoveInstr::new_uncond(ret_reg, RegisterOrImm::Reg(v_alloc.reg))); } self.instrs.push(MoveInstr::new_fp_to_sp()); self.instrs.push(PopInstr::new_pop_fp_pc()); @@ -98,10 +139,60 @@ impl Generator { self.instrs.push(SubInstr::new_sp(stack_size_needed as i32)); }, IRInstr::DefineFunc(_, _, _) => unreachable!(), - _ => unimplemented!(), + IRInstr::Cmp(variable, left, cmp_op, right) => self.emit_cmp(variable, left, cmp_op, right, &var_index_to_stack_offset), + IRInstr::Unary(variable, unary_op, variable1) => self.emit_unary(variable, unary_op, variable1, &var_index_to_stack_offset), + IRInstr::Goto(index) => self.instrs.push(BInstr::new(format!("label_{}_{}", func_name, index))), + IRInstr::CondGoto(variable, true_label_index, false_label_index) => { + let variable_alloc = load_variable(variable, &mut self.register_allocator, &var_index_to_stack_offset, &mut self.instrs); + let variable_reg = variable_alloc.reg; + self.instrs.push(CmpInstr::new(variable_reg, RegisterOrImm::Imm(0))); + self.instrs.push(BInstr::new_cond(ConditionCode::Ne, format!("label_{}_{}", func_name, true_label_index))); + self.instrs.push(BInstr::new(format!("label_{}_{}", func_name, false_label_index))); + + }, + IRInstr::Label(index) => self.instrs.push(ARMInstr::Label(format!("label_{}_{}", func_name, index))), } } } + fn emit_unary(&mut self, dest: Variable, unary_op: IRUnaryOp, variable: Variable, var_index_to_stack_offset: &BTreeMap) { + let variable_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let dest_alloc = self.register_allocator.alloc(dest).expect("Ran out of registers"); + match unary_op { + IRUnaryOp::Neg => { + self.instrs.push(RsbInstr::new(dest_alloc.reg, variable_alloc.reg, RegisterOrImm::Imm(0))); + }, + } + save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + } + fn emit_cmp(&mut self, variable: Variable, left: VariableOrIntLit, cmp_op: IRCmpOp, right: VariableOrIntLit, var_index_to_stack_offset: &BTreeMap) { + let left_alloc = match left { + VariableOrIntLit::Var(var) => { + load_variable(var, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs) + }, + VariableOrIntLit::IntLit(lit) => { + let alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); + self.instrs.push(MoveInstr::new_uncond(alloc.reg, RegisterOrImm::Imm(lit))); + alloc + }, + }; + // TODO: check left == right + let right_alloc = match right { + VariableOrIntLit::Var(var) => { + load_variable(var, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs) + }, + VariableOrIntLit::IntLit(lit) => { + let alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); + self.instrs.push(MoveInstr::new_uncond(alloc.reg, RegisterOrImm::Imm(lit))); + alloc + }, + }; + let variable_alloc = self.register_allocator.alloc(variable).expect("Ran out of registers"); + let variable_reg = variable_alloc.reg; + self.instrs.push(CmpInstr::new(left_alloc.reg, RegisterOrImm::Reg(right_alloc.reg))); + self.instrs.push(MoveInstr::new_uncond(variable_reg, RegisterOrImm::Imm(0))); + self.instrs.push(MoveInstr::new_cond(cmp_op.into(), variable_reg, RegisterOrImm::Imm(1))); + save_variable(variable, variable_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + } fn emit_func_call(&mut self, func: Function, args: Vec, ret: Option, var_index_to_stack_offset: &BTreeMap) { self.instrs.push(PushInstr::new_push_caller_save()); @@ -109,20 +200,15 @@ impl Generator { todo!("More than 4 arguments not supported yet"); } const ARG_REGS: [Register; 4] = [REG_R0, REG_R1, REG_R2, REG_R3]; + let mut arg_reg_allocs = Vec::new(); for (i, arg) in args.into_iter().enumerate() { - let arg_alloc = self.register_allocator.alloc(arg).expect("Ran out of registers"); - let arg_reg = arg_alloc.reg; - if !arg_alloc.is_reused { - let arg_stack_offset = var_index_to_stack_offset.get(&arg.index).expect("Variable not declared"); - self.instrs.push(LoadInstr::new_stack(arg_reg, *arg_stack_offset as i32)); - } - self.instrs.push(MoveInstr::new_uncond(ARG_REGS[i], RegisterOrImm::Reg(arg_reg))); + arg_reg_allocs.push(self.register_allocator.alloc_reg(ARG_REGS[i]).expect("Ran out of registers")); + let arg_alloc = load_variable(arg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + self.instrs.push(MoveInstr::new_uncond(ARG_REGS[i], RegisterOrImm::Reg(arg_alloc.reg))); } self.instrs.push(BlInstr::new(func.name.clone())); if let Some(ret) = ret { - let ret_alloc = self.register_allocator.alloc(ret).expect("Ran out of registers"); - let ret_reg = ret_alloc.reg; - self.instrs.push(MoveInstr::new_uncond(ret_reg, RegisterOrImm::Reg(REG_R0))); + save_variable(ret, REG_R0, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); } @@ -133,66 +219,47 @@ impl Generator { let dest_register = dest_alloc.reg; match src { MoveRValue::Var(variable) => { - if !dest_alloc.is_reused { - let var_stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not found"); - self.instrs.push(LoadInstr::new_stack(dest_register, *var_stack_offset as i32)); - } + let src_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Reg(src_alloc.reg))); }, MoveRValue::ConstInt(literal_int) => self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Imm(literal_int))), }; - match dest.var_type { - VariableType::Global => { - let address_reg = self.register_allocator.alloc_any().expect("Ran out of registers"); - self.instrs.push(LoadPseudoInstr::new(address_reg, format!("global_var_{}", dest.index))); - self.instrs.push(StoreInstr::new(dest_register, address_reg, None)); - }, - VariableType::ParamTemp => { - todo!() - }, - _ => { - let offset = *var_index_to_stack_offset.get(&dest.index).expect("Variable not declared"); - self.instrs.push(StoreInstr::new_stack(dest_register, offset as i32)); - } - } + save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); } fn emit_binary(&mut self, dest: Variable, left: Variable, op: IRBinaryOp, right: Variable, var_index_to_stack_offset: &BTreeMap) { - let left_alloc = self.register_allocator.alloc(left).expect("Ran out of registers"); - let right_alloc = self.register_allocator.alloc(right).expect("Ran out of registers"); let dest_alloc = self.register_allocator.alloc(dest).expect("Ran out of registers"); - let left_reg = left_alloc.reg; - let right_reg = right_alloc.reg; let dest_reg = dest_alloc.reg; - if !left_alloc.is_reused { - let left_offset = var_index_to_stack_offset.get(&left.index).expect("Variable not declared"); - self.instrs.push(LoadInstr::new_stack(left_reg, *left_offset as i32)); - - } - if !right_alloc.is_reused { - let right_offset = var_index_to_stack_offset.get(&right.index).expect("Variable not declared"); - self.instrs.push(LoadInstr::new_stack(right_reg, *right_offset as i32)); - } + // should consider left == right + let left_alloc = load_variable(left, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let (_right_alloc, right_reg) = if left != right { + let right_alloc = load_variable(right, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); + let right_reg = right_alloc.reg; + (Some(right_alloc), right_reg) + } else { + (None, left_alloc.reg) + }; match op { IRBinaryOp::Add => { - self.instrs.push(AddInstr::new(dest_reg, left_reg, RegisterOrImm::Reg(right_reg))); + self.instrs.push(AddInstr::new(dest_reg, left_alloc.reg, RegisterOrImm::Reg(right_reg))); }, IRBinaryOp::Sub => { - self.instrs.push(SubInstr::new(dest_reg, left_reg, RegisterOrImm::Reg(right_reg))); + self.instrs.push(SubInstr::new(dest_reg, left_alloc.reg, RegisterOrImm::Reg(right_reg))); }, IRBinaryOp::Mul => { - self.instrs.push(MulInstr::new(dest_reg, left_reg, RegisterOrImm::Reg(right_reg))); + self.instrs.push(MulInstr::new(dest_reg, left_alloc.reg, RegisterOrImm::Reg(right_reg))); }, IRBinaryOp::Div => { - self.instrs.push(SDivInstr::new(dest_reg, left_reg, RegisterOrImm::Reg(right_reg))); + self.instrs.push(SDivInstr::new(dest_reg, left_alloc.reg, RegisterOrImm::Reg(right_reg))); }, IRBinaryOp::Mod => { - let temp_reg = self.register_allocator.alloc_any().expect("Ran out of registers"); - self.instrs.push(SDivInstr::new(temp_reg, left_reg, RegisterOrImm::Reg(right_reg))); + let temp_alloc = self.register_allocator.alloc_any().expect("Ran out of registers"); + let temp_reg = temp_alloc.reg; + self.instrs.push(SDivInstr::new(temp_reg, left_alloc.reg, RegisterOrImm::Reg(right_reg))); self.instrs.push(MulInstr::new(temp_reg, temp_reg, RegisterOrImm::Reg(right_reg))); - self.instrs.push(SubInstr::new(dest_reg, left_reg, RegisterOrImm::Reg(temp_reg))); + self.instrs.push(SubInstr::new(dest_reg, left_alloc.reg, RegisterOrImm::Reg(temp_reg))); }, } - let dest_stack_offset = var_index_to_stack_offset.get(&dest.index).expect("Variable not declared"); - self.instrs.push(StoreInstr::new_stack(dest_reg, *dest_stack_offset as i32)); + save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs); } } \ No newline at end of file diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 9ce6647..30c6c5e 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -74,4 +74,8 @@ mod tests { test_case("0-3,14-25"); // test_case("0-3,14-25"); } + #[test] + fn test_if_while() { + test_case("26-32,34-41,46-51,57"); + } } \ No newline at end of file diff --git a/src/backend/register_allocator.rs b/src/backend/register_allocator.rs index 347e87e..a1ff524 100644 --- a/src/backend/register_allocator.rs +++ b/src/backend/register_allocator.rs @@ -109,6 +109,9 @@ impl RegisterAllocator { // Variable already has a register allocated let use_kind = inner.register_map.get_mut(®).expect("Inconsistent state: variable has a register but it's not in the register map"); assert!(matches!(use_kind, RegisterUseKind::UsedByVariable(v) | RegisterUseKind::AllocatedToVariable(v) if *v == var)); + if matches!(use_kind, RegisterUseKind::UsedByVariable(_)) { + panic!("variable already actively borrowed"); + } *use_kind = RegisterUseKind::UsedByVariable(var); return Some(RegisterAlloc { allocator: Rc::downgrade(&self.inner), @@ -179,13 +182,17 @@ impl RegisterAllocator { } - pub fn alloc_any(&mut self) -> Option { + pub fn alloc_any(&mut self) -> Option { let mut inner = self.inner.borrow_mut(); for (®, use_kind) in inner.register_map.iter_mut() { if let RegisterUseKind::Free = use_kind { *use_kind = RegisterUseKind::Designated; - return Some(reg); + return Some(RegisterAlloc { + allocator: Rc::downgrade(&self.inner), + reg, + is_reused: false, + }); } } let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner; @@ -193,7 +200,11 @@ impl RegisterAllocator { if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind { variable_to_register.remove(&ori_var); *use_kind = RegisterUseKind::Designated; - return Some(reg); + return Some(RegisterAlloc { + allocator: Rc::downgrade(&self.inner), + reg, + is_reused: false, + }); } }