1use rucc_ir::Type;
11
12use super::{Insts, place};
13
14pub static INSTS: Insts = Insts {
16 arg: head_of,
17 load: load_of,
18 store: store_of,
19 ret: ret_of,
20 call: "a64.bl",
21 call_reg: "a64.blr",
22 lea: "a64.lea_64",
23 small: "a64.mov_ri_32",
24};
25
26fn head_of(ty: Type) -> Option<&'static str> {
28 if crate::term::is_quad(ty) {
29 return Some("a64.arg_val_f128");
30 }
31 if crate::term::is_half(ty) {
32 return None;
33 }
34 if let Some(at) = crate::term::float_slot(ty) {
35 return Some(["a64.arg_val_f32", "a64.arg_val_f64"][at]);
36 }
37 let names = ["a64.arg_val_32", "a64.arg_val_32", "a64.arg_val_32", "a64.arg_val_64"];
38 Some(names[place(ty)?])
39}
40
41fn load_of(ty: Type) -> Option<&'static str> {
46 if crate::term::is_quad(ty) {
47 return Some("a64.ldr_f128");
48 }
49 if crate::term::is_half(ty) {
50 return None;
51 }
52 if let Some(at) = crate::term::float_slot(ty) {
53 return Some(["a64.ldr_f32", "a64.ldr_f64"][at]);
54 }
55 let names = ["a64.ldr_8", "a64.ldr_16", "a64.ldr_32", "a64.ldr_64"];
56 Some(names[place(ty)?])
57}
58
59fn store_of(ty: Type) -> Option<&'static str> {
61 if crate::term::is_quad(ty) {
62 return Some("a64.str_f128");
63 }
64 if crate::term::is_half(ty) {
65 return None;
66 }
67 if let Some(at) = crate::term::float_slot(ty) {
68 return Some(["a64.str_f32", "a64.str_f64"][at]);
69 }
70 let names = ["a64.str_8", "a64.str_16", "a64.str_32", "a64.str_64"];
71 Some(names[place(ty)?])
72}
73
74fn ret_of(ty: Type, at: usize) -> Option<&'static str> {
81 if crate::term::is_quad(ty) {
82 let names =
83 ["a64.ret_val_f128", "a64.ret_val2_f128", "a64.ret_val3_f128", "a64.ret_val4_f128"];
84 return Some(*names.get(at)?);
85 }
86 if crate::term::is_half(ty) {
87 return None;
88 }
89 if let Some(width) = crate::term::float_slot(ty) {
90 let names = [
93 ["a64.ret_val_f32", "a64.ret_val_f64"],
94 ["a64.ret_val2_f32", "a64.ret_val2_f64"],
95 ["a64.ret_val3_f32", "a64.ret_val3_f64"],
96 ["a64.ret_val4_f32", "a64.ret_val4_f64"],
97 ];
98 return Some(names.get(at)?[width]);
99 }
100 let names = [
101 ["a64.ret_val_32", "a64.ret_val_32", "a64.ret_val_32", "a64.ret_val_64"],
102 ["a64.ret_val2_32", "a64.ret_val2_32", "a64.ret_val2_32", "a64.ret_val2_64"],
103 ];
104 Some(names.get(at)?[place(ty)?])
105}
106
107#[cfg(test)]
108mod tests {
109 use rucc_ir::{Float, Type};
110 use rucc_target::aarch64;
111
112 use super::*;
113
114 fn types() -> Vec<Type> {
116 let mut types: Vec<Type> = [1, 8, 16, 32, 64, 128].into_iter().map(Type::int).collect();
117 types
118 .extend([Float::F16, Float::F32, Float::F64, Float::F80, Float::F128].map(Type::float));
119 types.push(Type::PTR);
120 types
121 }
122
123 #[test]
124 fn every_name_is_an_instruction_the_machine_describes() {
125 let described = |name: &str| {
126 let bare = name.strip_prefix("a64.").expect("an AArch64 name");
127 assert!(aarch64::form(bare).is_some(), "{name}");
128 };
129 for ty in types() {
130 for name in [head_of(ty), load_of(ty), store_of(ty)]
131 .into_iter()
132 .chain((0..4).map(|at| ret_of(ty, at)))
133 {
134 name.map(described);
135 }
136 }
137 for name in [INSTS.call, INSTS.call_reg, INSTS.lea, INSTS.small] {
138 described(name);
139 }
140 }
141
142 #[test]
143 fn the_four_answer_for_the_same_types() {
144 for ty in types() {
145 let arrives = head_of(ty).is_some();
146 assert_eq!(arrives, load_of(ty).is_some(), "{ty:?}");
147 assert_eq!(arrives, store_of(ty).is_some(), "{ty:?}");
148 assert_eq!(arrives, ret_of(ty, 0).is_some(), "{ty:?}");
149 }
150 }
151
152 #[test]
153 fn a_narrow_integer_travels_in_a_32_bit_register_and_is_read_at_its_own_width() {
154 assert_eq!(head_of(Type::int(8)), Some("a64.arg_val_32"));
155 assert_eq!(head_of(Type::int(16)), Some("a64.arg_val_32"));
156 assert_eq!(head_of(Type::PTR), Some("a64.arg_val_64"));
157 assert_eq!(load_of(Type::int(8)), Some("a64.ldr_8"));
158 assert_eq!(store_of(Type::int(16)), Some("a64.str_16"));
159 assert_eq!(ret_of(Type::int(1), 0), Some("a64.ret_val_32"));
160 assert_eq!(ret_of(Type::int(64), 1), Some("a64.ret_val2_64"));
161 assert_eq!(ret_of(Type::int(64), 2), None);
162 }
163
164 #[test]
167 fn a_floating_point_aggregate_comes_back_in_up_to_four_registers() {
168 assert_eq!(ret_of(Type::float(Float::F32), 2), Some("a64.ret_val3_f32"));
169 assert_eq!(ret_of(Type::float(Float::F64), 3), Some("a64.ret_val4_f64"));
170 assert_eq!(ret_of(Type::float(Float::F128), 3), Some("a64.ret_val4_f128"));
171 assert_eq!(ret_of(Type::float(Float::F64), 4), None);
172 }
173
174 #[test]
175 fn a_long_double_is_a_quad_and_a_half_is_not_passed_yet() {
176 assert_eq!(head_of(Type::float(Float::F128)), Some("a64.arg_val_f128"));
177 assert_eq!(head_of(Type::float(Float::F16)), None);
178 assert_eq!(head_of(Type::int(128)), None);
179 }
180}