lamina_codegen/aarch64/
abi.rs1use crate::abi::{Abi, common_call_stub, mangle_macos_name};
4use crate::target_support::os_uses_macho;
5use lamina_platform::TargetOperatingSystem;
6
7pub struct AArch64ABI {
9 target_os: TargetOperatingSystem,
10}
11
12impl AArch64ABI {
13 pub fn new(target_os: TargetOperatingSystem) -> Self {
15 Self { target_os }
16 }
17
18 pub fn mangle_function_name(&self, name: &str) -> String {
20 match self.target_os {
21 os if os_uses_macho(os) => mangle_macos_name(name),
22 _ => name.to_string(),
23 }
24 }
25
26 pub fn get_global_directive(&self, func_name: &str) -> Option<String> {
28 match self.target_os {
29 os if os_uses_macho(os) => Some(format!(".globl _{func_name}")),
30 _ => Some(format!(".globl {func_name}")),
31 }
32 }
33
34 pub fn call_stub(&self, name: &str) -> Option<String> {
36 common_call_stub(name, self.target_os)
37 }
38
39 pub const ARG_REGISTERS: &'static [&'static str] =
41 &["x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"];
42
43 pub const CALLER_SAVED_REGISTERS: &'static [&'static str] = &[
45 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13",
46 "x14", "x15", "x16", "x17",
47 ];
48
49 pub const CALLEE_SAVED_REGISTERS: &'static [&'static str] = &[
51 "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30",
52 ];
53
54 pub fn target_os(&self) -> TargetOperatingSystem {
56 self.target_os
57 }
58}
59
60impl Abi for AArch64ABI {
61 fn target_os(&self) -> TargetOperatingSystem {
62 self.target_os
63 }
64
65 fn mangle_function_name(&self, name: &str) -> String {
66 AArch64ABI::mangle_function_name(self, name)
67 }
68
69 fn call_stub(&self, name: &str) -> Option<String> {
70 AArch64ABI::call_stub(self, name)
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_aarch64_mangle_function_name() {
80 let abi_linux = AArch64ABI::new(TargetOperatingSystem::Linux);
81 assert_eq!(abi_linux.mangle_function_name("main"), "main");
82 assert_eq!(abi_linux.mangle_function_name("foo"), "foo");
83 assert_eq!(abi_linux.mangle_function_name("my_func"), "my_func");
84
85 let abi_macos = AArch64ABI::new(TargetOperatingSystem::MacOS);
86 assert_eq!(abi_macos.mangle_function_name("main"), "_main");
87 assert_eq!(abi_macos.mangle_function_name("foo"), "_foo");
88 assert_eq!(abi_macos.mangle_function_name("my_func"), "_my_func");
89 }
90
91 #[test]
92 fn test_aarch64_call_stub() {
93 let abi_linux = AArch64ABI::new(TargetOperatingSystem::Linux);
94 assert_eq!(abi_linux.call_stub("malloc"), Some("malloc".to_string()));
95 assert_eq!(abi_linux.call_stub("dealloc"), Some("free".to_string()));
96 assert_eq!(abi_linux.call_stub("unknown"), None);
97
98 let abi_macos = AArch64ABI::new(TargetOperatingSystem::MacOS);
99 assert_eq!(abi_macos.call_stub("malloc"), Some("_malloc".to_string()));
100 }
101
102 #[test]
103 fn test_aarch64_arg_registers() {
104 assert_eq!(AArch64ABI::ARG_REGISTERS.len(), 8);
105 assert_eq!(AArch64ABI::ARG_REGISTERS[0], "x0");
106 assert_eq!(AArch64ABI::ARG_REGISTERS[7], "x7");
107 }
108
109 #[test]
110 fn test_aarch64_caller_saved_registers() {
111 assert_eq!(AArch64ABI::CALLER_SAVED_REGISTERS.len(), 18);
112 assert!(AArch64ABI::CALLER_SAVED_REGISTERS.contains(&"x0"));
113 assert!(AArch64ABI::CALLER_SAVED_REGISTERS.contains(&"x15"));
114 }
115
116 #[test]
117 fn test_aarch64_callee_saved_registers() {
118 assert_eq!(AArch64ABI::CALLEE_SAVED_REGISTERS.len(), 12);
119 assert!(AArch64ABI::CALLEE_SAVED_REGISTERS.contains(&"x19"));
120 assert!(AArch64ABI::CALLEE_SAVED_REGISTERS.contains(&"x30"));
121 }
122
123 #[test]
124 fn test_aarch64_get_global_directive() {
125 let abi_linux = AArch64ABI::new(TargetOperatingSystem::Linux);
126 assert_eq!(
127 abi_linux.get_global_directive("main"),
128 Some(".globl main".to_string())
129 );
130 assert_eq!(
131 abi_linux.get_global_directive("foo"),
132 Some(".globl foo".to_string())
133 );
134
135 let abi_macos = AArch64ABI::new(TargetOperatingSystem::MacOS);
136 assert_eq!(
137 abi_macos.get_global_directive("main"),
138 Some(".globl _main".to_string())
139 );
140 assert_eq!(
141 abi_macos.get_global_directive("foo"),
142 Some(".globl _foo".to_string())
143 );
144
145 let abi_ios = AArch64ABI::new(TargetOperatingSystem::IOS);
146 assert_eq!(abi_ios.mangle_function_name("main"), "_main");
147 assert_eq!(
148 abi_ios.get_global_directive("main"),
149 Some(".globl _main".to_string())
150 );
151 }
152}