use std::io::{self, Write};
const LINKAGE_SIZE: usize = 32;
pub struct Ppc64Frame;
impl Ppc64Frame {
pub fn aligned_frame_size(local_bytes: usize) -> usize {
((LINKAGE_SIZE + local_bytes) + 15) & !15
}
pub fn calculate_stack_offset(slot: usize) -> i32 {
(LINKAGE_SIZE + slot * 8) as i32
}
pub fn generate_prologue<W: Write>(writer: &mut W, local_bytes: usize) -> io::Result<()> {
let frame_size = Self::aligned_frame_size(local_bytes);
writeln!(writer, " mflr 0")?;
writeln!(writer, " std 0, 16(1)")?; writeln!(writer, " stdu 1, -{}(1)", frame_size)?; Ok(())
}
pub fn generate_epilogue<W: Write>(writer: &mut W, local_bytes: usize) -> io::Result<()> {
let frame_size = Self::aligned_frame_size(local_bytes);
writeln!(writer, " addi 1, 1, {}", frame_size)?; writeln!(writer, " ld 0, 16(1)")?; writeln!(writer, " mtlr 0")?;
writeln!(writer, " blr")?;
Ok(())
}
pub fn generate_tail_epilogue<W: Write>(writer: &mut W, local_bytes: usize) -> io::Result<()> {
let frame_size = Self::aligned_frame_size(local_bytes);
writeln!(writer, " addi 1, 1, {}", frame_size)?;
writeln!(writer, " ld 0, 16(1)")?;
writeln!(writer, " mtlr 0")?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stack_offset_slot_0() {
assert_eq!(Ppc64Frame::calculate_stack_offset(0), LINKAGE_SIZE as i32);
}
#[test]
fn test_stack_offset_slot_1() {
assert_eq!(
Ppc64Frame::calculate_stack_offset(1),
(LINKAGE_SIZE + 8) as i32
);
}
#[test]
fn test_prologue_emits_stdu() {
let mut buf = Vec::new();
Ppc64Frame::generate_prologue(&mut buf, 0).unwrap();
let s = String::from_utf8(buf).unwrap();
assert!(s.contains("stdu"), "Expected stdu in prologue: {s}");
assert!(s.contains("mflr"), "Expected mflr in prologue: {s}");
}
#[test]
fn test_epilogue_emits_blr() {
let mut buf = Vec::new();
Ppc64Frame::generate_epilogue(&mut buf, 0).unwrap();
let s = String::from_utf8(buf).unwrap();
assert!(s.contains("blr"), "Expected blr in epilogue: {s}");
assert!(s.contains("mtlr"), "Expected mtlr in epilogue: {s}");
}
#[test]
fn test_tail_epilogue_has_no_blr() {
let mut buf = Vec::new();
Ppc64Frame::generate_tail_epilogue(&mut buf, 0).unwrap();
let s = String::from_utf8(buf).unwrap();
assert!(!s.contains("blr"), "tail epilogue must not return: {s}");
assert!(s.contains("mtlr"), "Expected mtlr: {s}");
}
}