use crate::mir_codegen::abi::{Abi, common_call_stub, mangle_macos_name};
use lamina_platform::TargetOperatingSystem;
pub struct RiscVAbi {
target_os: TargetOperatingSystem,
}
impl RiscVAbi {
pub fn new(target_os: TargetOperatingSystem) -> Self {
Self { target_os }
}
pub fn mangle_function_name(&self, name: &str) -> String {
match self.target_os {
TargetOperatingSystem::MacOS => mangle_macos_name(name),
_ => name.to_string(),
}
}
pub fn get_main_global(&self) -> &'static str {
".globl main"
}
pub fn get_data_section(&self) -> &'static str {
".data"
}
pub fn get_text_section(&self) -> &'static str {
".text"
}
pub fn get_print_format(&self) -> &'static str {
match self.target_os {
TargetOperatingSystem::MacOS => "__mir_fmt_int: .asciz \"%lld\\n\"",
_ => ".L_mir_fmt_int: .string \"%lld\\n\"",
}
}
pub const ARG_REGISTERS: &'static [&'static str] =
&["a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7"];
pub fn call_stub(&self, name: &str) -> Option<String> {
common_call_stub(name, self.target_os)
}
}
impl Abi for RiscVAbi {
fn target_os(&self) -> TargetOperatingSystem {
self.target_os
}
fn mangle_function_name(&self, name: &str) -> String {
RiscVAbi::mangle_function_name(self, name)
}
fn call_stub(&self, name: &str) -> Option<String> {
RiscVAbi::call_stub(self, name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_riscv_abi_new() {
let abi = RiscVAbi::new(TargetOperatingSystem::Linux);
assert_eq!(abi.target_os(), TargetOperatingSystem::Linux);
let abi_macos = RiscVAbi::new(TargetOperatingSystem::MacOS);
assert_eq!(abi_macos.target_os(), TargetOperatingSystem::MacOS);
}
#[test]
fn test_riscv_mangle_function_name() {
let abi_linux = RiscVAbi::new(TargetOperatingSystem::Linux);
assert_eq!(abi_linux.mangle_function_name("main"), "main");
assert_eq!(abi_linux.mangle_function_name("foo"), "foo");
assert_eq!(abi_linux.mangle_function_name("my_func"), "my_func");
let abi_macos = RiscVAbi::new(TargetOperatingSystem::MacOS);
assert_eq!(abi_macos.mangle_function_name("main"), "_main");
assert_eq!(abi_macos.mangle_function_name("foo"), "_foo");
assert_eq!(abi_macos.mangle_function_name("my_func"), "_my_func");
}
#[test]
fn test_riscv_call_stub() {
let abi_linux = RiscVAbi::new(TargetOperatingSystem::Linux);
assert_eq!(abi_linux.call_stub("print"), Some("printf".to_string()));
assert_eq!(abi_linux.call_stub("malloc"), Some("malloc".to_string()));
assert_eq!(abi_linux.call_stub("dealloc"), Some("free".to_string()));
assert_eq!(abi_linux.call_stub("unknown"), None);
let abi_macos = RiscVAbi::new(TargetOperatingSystem::MacOS);
assert_eq!(abi_macos.call_stub("print"), Some("_printf".to_string()));
assert_eq!(abi_macos.call_stub("malloc"), Some("_malloc".to_string()));
assert_eq!(abi_macos.call_stub("dealloc"), Some("_free".to_string()));
}
#[test]
fn test_riscv_arg_registers() {
assert_eq!(RiscVAbi::ARG_REGISTERS.len(), 8);
assert_eq!(RiscVAbi::ARG_REGISTERS[0], "a0");
assert_eq!(RiscVAbi::ARG_REGISTERS[7], "a7");
}
#[test]
fn test_riscv_get_main_global() {
let abi = RiscVAbi::new(TargetOperatingSystem::Linux);
assert_eq!(abi.get_main_global(), ".globl main");
}
#[test]
fn test_riscv_get_print_format() {
let abi_linux = RiscVAbi::new(TargetOperatingSystem::Linux);
assert_eq!(
abi_linux.get_print_format(),
".L_mir_fmt_int: .string \"%lld\\n\""
);
let abi_macos = RiscVAbi::new(TargetOperatingSystem::MacOS);
assert_eq!(
abi_macos.get_print_format(),
"__mir_fmt_int: .asciz \"%lld\\n\""
);
}
}