Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 52 additions & 66 deletions crates/rue-codegen/src/aarch64/cfg_lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ impl<'a> CfgLower<'a> {
}
}

/// Intern a symbol name and return its ID.
///
/// Convenience method that delegates to the MIR's symbol table.
fn intern_symbol(&mut self, symbol: &str) -> u32 {
self.mir.intern_symbol(symbol)
}

/// Get the length of an array type.
fn array_length(&self, array_type_id: ArrayTypeId) -> u64 {
debug_assert!(
Expand Down Expand Up @@ -302,9 +309,8 @@ impl<'a> CfgLower<'a> {
});

// Call the bounds check error handler (never returns)
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_bounds_check".to_string(),
});
let symbol_id = self.intern_symbol("__rue_bounds_check");
self.mir.push(Aarch64Inst::Bl { symbol_id });

// Continue with valid access
self.mir.push(Aarch64Inst::Label { id: ok_label });
Expand Down Expand Up @@ -843,9 +849,8 @@ impl<'a> CfgLower<'a> {
src: Operand::Virtual(rhs_vreg),
label: ok_label,
});
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_div_by_zero".to_string(),
});
let symbol_id = self.intern_symbol("__rue_div_by_zero");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });

self.mir.push(Aarch64Inst::SdivRR {
Expand All @@ -868,9 +873,8 @@ impl<'a> CfgLower<'a> {
src: Operand::Virtual(rhs_vreg),
label: ok_label,
});
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_div_by_zero".to_string(),
});
let symbol_id = self.intern_symbol("__rue_div_by_zero");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });

// Compute quotient first
Expand Down Expand Up @@ -1698,9 +1702,9 @@ impl<'a> CfgLower<'a> {
}

// Call the function - the linker will add the underscore prefix for macOS
self.mir.push(Aarch64Inst::Bl {
symbol: self.interner.get(*name).to_string(),
});
let symbol_name = self.interner.get(*name);
let symbol_id = self.intern_symbol(symbol_name);
self.mir.push(Aarch64Inst::Bl { symbol_id });

// Clean up stack space after call
if stack_space > 0 {
Expand Down Expand Up @@ -1790,9 +1794,8 @@ impl<'a> CfgLower<'a> {
});

// Call __rue_dbg_str
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_dbg_str".to_string(),
});
let symbol_id = self.intern_symbol("__rue_dbg_str");
self.mir.push(Aarch64Inst::Bl { symbol_id });
} else {
unreachable!("String fat pointer not found in struct_slot_vregs");
}
Expand Down Expand Up @@ -1871,9 +1874,8 @@ impl<'a> CfgLower<'a> {
_ => unreachable!(),
}

self.mir.push(Aarch64Inst::Bl {
symbol: runtime_fn.to_string(),
});
let symbol_id = self.intern_symbol(runtime_fn);
self.mir.push(Aarch64Inst::Bl { symbol_id });

let result_vreg = self.mir.alloc_vreg();
self.value_map.insert(value, result_vreg);
Expand Down Expand Up @@ -2426,9 +2428,8 @@ impl<'a> CfgLower<'a> {
src: Operand::Virtual(field_vregs[2]), // cap
});

self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_drop_String".to_string(),
});
let symbol_id = self.intern_symbol("__rue_drop_String");
self.mir.push(Aarch64Inst::Bl { symbol_id });
return;
}

Expand Down Expand Up @@ -2457,9 +2458,8 @@ impl<'a> CfgLower<'a> {
src: Operand::Virtual(*vreg),
});
}
self.mir.push(Aarch64Inst::Bl {
symbol: destructor_name.clone(),
});
let symbol_id = self.intern_symbol(destructor_name);
self.mir.push(Aarch64Inst::Bl { symbol_id });
}

// Now call the drop glue function to drop fields
Expand All @@ -2472,9 +2472,8 @@ impl<'a> CfgLower<'a> {
}

let drop_fn_name = format!("__rue_drop_{}", struct_def.name);
self.mir.push(Aarch64Inst::Bl {
symbol: drop_fn_name,
});
let symbol_id = self.intern_symbol(&drop_fn_name);
self.mir.push(Aarch64Inst::Bl { symbol_id });
return;
}

Expand Down Expand Up @@ -2618,9 +2617,8 @@ impl<'a> CfgLower<'a> {
}

// Overflow occurred - call panic handler
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });
}

Expand Down Expand Up @@ -2653,9 +2651,8 @@ impl<'a> CfgLower<'a> {
_ => return,
}

self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });
}

Expand Down Expand Up @@ -2794,9 +2791,8 @@ impl<'a> CfgLower<'a> {
_ => return,
}

self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });
}

Expand Down Expand Up @@ -2836,9 +2832,8 @@ impl<'a> CfgLower<'a> {
_ => return,
}

self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });
}

Expand Down Expand Up @@ -2896,9 +2891,8 @@ impl<'a> CfgLower<'a> {
});

// Below min - panic
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_intcast_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_intcast_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });

let ok_label2 = self.mir.alloc_label();
Expand All @@ -2919,9 +2913,8 @@ impl<'a> CfgLower<'a> {
});

// Above max - panic
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_intcast_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_intcast_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label2 });
}
} else {
Expand Down Expand Up @@ -2969,9 +2962,8 @@ impl<'a> CfgLower<'a> {
});

// Negative - panic
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_intcast_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_intcast_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });

// Also check upper bound if narrowing
Expand All @@ -2993,9 +2985,8 @@ impl<'a> CfgLower<'a> {
});

// Above max - panic
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_intcast_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_intcast_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label2 });
}
}
Expand All @@ -3020,9 +3011,8 @@ impl<'a> CfgLower<'a> {
});

// Above max - panic
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_intcast_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_intcast_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });
} else {
// Unsigned to unsigned: narrowing check
Expand All @@ -3042,9 +3032,8 @@ impl<'a> CfgLower<'a> {
});

// Above max - panic
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_intcast_overflow".to_string(),
});
let symbol_id = self.intern_symbol("__rue_intcast_overflow");
self.mir.push(Aarch64Inst::Bl { symbol_id });
self.mir.push(Aarch64Inst::Label { id: ok_label });
}
}
Expand Down Expand Up @@ -3127,9 +3116,8 @@ impl<'a> CfgLower<'a> {
});

// Call __rue_str_eq
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_str_eq".to_string(),
});
let symbol_id = self.intern_symbol("__rue_str_eq");
self.mir.push(Aarch64Inst::Bl { symbol_id });

// Result is in X0 (0 or 1)
self.mir.push(Aarch64Inst::MovRR {
Expand Down Expand Up @@ -3318,9 +3306,8 @@ impl<'a> CfgLower<'a> {
});

// Call __rue_str_eq
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_str_eq".to_string(),
});
let symbol_id = self.intern_symbol("__rue_str_eq");
self.mir.push(Aarch64Inst::Bl { symbol_id });

// Result is in X0 (0 or 1)
self.mir.push(Aarch64Inst::MovRR {
Expand Down Expand Up @@ -3476,9 +3463,8 @@ impl<'a> CfgLower<'a> {
dst: Operand::Physical(Reg::X0),
src: Operand::Virtual(val_vreg),
});
self.mir.push(Aarch64Inst::Bl {
symbol: "__rue_exit".to_string(),
});
let symbol_id = self.intern_symbol("__rue_exit");
self.mir.push(Aarch64Inst::Bl { symbol_id });
} else if let Type::Struct(struct_id) = return_type {
// Return struct in registers
let slot_count = self.type_slot_count(Type::Struct(struct_id));
Expand Down
8 changes: 4 additions & 4 deletions crates/rue-codegen/src/aarch64/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,8 @@ impl<'a> Emitter<'a> {
self.record_label(format!("L{}", id));
}

Aarch64Inst::Bl { symbol } => {
Aarch64Inst::Bl { symbol_id } => {
let symbol = self.mir.get_symbol(*symbol_id);
self.begin_inst();
self.emit_bl(symbol);
self.end_inst(format!("bl {}", symbol));
Expand Down Expand Up @@ -2537,9 +2538,8 @@ mod tests {
use crate::RelocationKind;

let mut mir = Aarch64Mir::new();
mir.push(Aarch64Inst::Bl {
symbol: "test_func".to_string(),
});
let symbol_id = mir.intern_symbol("test_func");
mir.push(Aarch64Inst::Bl { symbol_id });

let (code, relocs) = Emitter::new(&mir, 0, 0, &[], &[]).emit().unwrap();

Expand Down
63 changes: 60 additions & 3 deletions crates/rue-codegen/src/aarch64/mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,9 @@ pub enum Aarch64Inst {
Label { id: LabelId },

/// `bl symbol` - Branch with link (call).
Bl { symbol: String },
///
/// The `symbol_id` is an index into the symbol table stored in `Aarch64Mir`.
Bl { symbol_id: u32 },

/// `ret` - Return (branch to LR).
Ret,
Expand Down Expand Up @@ -909,7 +911,7 @@ impl fmt::Display for Aarch64Inst {
Aarch64Inst::Bvs { label } => write!(f, "b.vs {}", label),
Aarch64Inst::Bvc { label } => write!(f, "b.vc {}", label),
Aarch64Inst::Label { id } => write!(f, "{}:", id),
Aarch64Inst::Bl { symbol } => write!(f, "bl {}", symbol),
Aarch64Inst::Bl { symbol_id } => write!(f, "bl sym{}", symbol_id),
Aarch64Inst::Ret => write!(f, "ret"),
Aarch64Inst::StpPre { src1, src2, offset } => {
write!(f, "stp {}, {}, [sp, #{}]!", src1, src2, offset)
Expand Down Expand Up @@ -942,6 +944,11 @@ pub struct Aarch64Mir {
/// Inline labels (for overflow checks, bounds checks, etc.) use IDs from
/// the lower half of the `u32` space. See module docs for namespace details.
next_label: u32,
/// Symbol table for call targets.
///
/// Stores symbol names indexed by `symbol_id` in `Bl` instructions.
/// This avoids heap-allocating a String for every call instruction.
symbols: Vec<String>,
}

impl Aarch64Mir {
Expand All @@ -951,7 +958,52 @@ impl Aarch64Mir {
instructions: Vec::new(),
next_vreg: 0,
next_label: 0,
symbols: Vec::new(),
}
}

/// Intern a symbol name and return its ID.
///
/// If the symbol already exists, returns its existing ID.
/// Otherwise, adds it to the table and returns the new ID.
pub fn intern_symbol(&mut self, symbol: &str) -> u32 {
// Check if symbol already exists
if let Some(idx) = self.symbols.iter().position(|s| s == symbol) {
return idx as u32;
}
// Add new symbol
let idx = self.symbols.len() as u32;
self.symbols.push(symbol.to_string());
idx
}

/// Get a symbol name by its ID.
///
/// # Panics
/// Panics if the symbol_id is out of bounds.
#[inline]
pub fn get_symbol(&self, symbol_id: u32) -> &str {
&self.symbols[symbol_id as usize]
}

/// Get the symbol table.
#[inline]
pub fn symbols(&self) -> &[String] {
&self.symbols
}

/// Take ownership of the symbol table.
///
/// Used during register allocation to transfer symbols to the new MIR.
pub fn take_symbols(&mut self) -> Vec<String> {
std::mem::take(&mut self.symbols)
}

/// Set the symbol table.
///
/// Used during register allocation to restore symbols from the old MIR.
pub fn set_symbols(&mut self, symbols: Vec<String>) {
self.symbols = symbols;
}

/// Allocate a new virtual register.
Expand Down Expand Up @@ -1029,7 +1081,12 @@ impl Aarch64Mir {
impl fmt::Display for Aarch64Mir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for inst in &self.instructions {
writeln!(f, " {}", inst)?;
// Special handling for Bl to show actual symbol name
if let Aarch64Inst::Bl { symbol_id } = inst {
writeln!(f, " bl {}", self.get_symbol(*symbol_id))?;
} else {
writeln!(f, " {}", inst)?;
}
}
Ok(())
}
Expand Down
Loading