1 //! ARM ABI implementation.
2 //! This is from the RISC-V target and will need to be updated for ARM32.
3 
4 use super::registers::{D, GPR, Q, S};
5 use crate::abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
6 use crate::ir::{self, AbiParam, ArgumentExtension, ArgumentLoc, Type};
7 use crate::isa::RegClass;
8 use crate::regalloc::RegisterSet;
9 use alloc::borrow::Cow;
10 use core::i32;
11 use target_lexicon::Triple;
12 
13 struct Args {
14     pointer_bits: u8,
15     pointer_bytes: u8,
16     pointer_type: Type,
17     regs: u32,
18     reg_limit: u32,
19     offset: u32,
20 }
21 
22 impl Args {
new(bits: u8) -> Self23     fn new(bits: u8) -> Self {
24         Self {
25             pointer_bits: bits,
26             pointer_bytes: bits / 8,
27             pointer_type: Type::int(u16::from(bits)).unwrap(),
28             regs: 0,
29             reg_limit: 8,
30             offset: 0,
31         }
32     }
33 }
34 
35 impl ArgAssigner for Args {
assign(&mut self, arg: &AbiParam) -> ArgAction36     fn assign(&mut self, arg: &AbiParam) -> ArgAction {
37         fn align(value: u32, to: u32) -> u32 {
38             (value + to - 1) & !(to - 1)
39         }
40 
41         let ty = arg.value_type;
42 
43         // Check for a legal type.
44         // SIMD instructions are currently no implemented, so break down vectors
45         if ty.is_vector() {
46             return ValueConversion::VectorSplit.into();
47         }
48 
49         // Large integers and booleans are broken down to fit in a register.
50         if !ty.is_float() && ty.bits() > u16::from(self.pointer_bits) {
51             // Align registers and stack to a multiple of two pointers.
52             self.regs = align(self.regs, 2);
53             self.offset = align(self.offset, 2 * u32::from(self.pointer_bytes));
54             return ValueConversion::IntSplit.into();
55         }
56 
57         // Small integers are extended to the size of a pointer register.
58         if ty.is_int() && ty.bits() < u16::from(self.pointer_bits) {
59             match arg.extension {
60                 ArgumentExtension::None => {}
61                 ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(),
62                 ArgumentExtension::Sext => return ValueConversion::Sext(self.pointer_type).into(),
63             }
64         }
65 
66         if self.regs < self.reg_limit {
67             // Assign to a register.
68             let reg = GPR.unit(10 + self.regs as usize);
69             self.regs += 1;
70             ArgumentLoc::Reg(reg).into()
71         } else {
72             // Assign a stack location.
73             let loc = ArgumentLoc::Stack(self.offset as i32);
74             self.offset += u32::from(self.pointer_bytes);
75             debug_assert!(self.offset <= i32::MAX as u32);
76             loc.into()
77         }
78     }
79 }
80 
81 /// Legalize `sig`.
legalize_signature(sig: &mut Cow<ir::Signature>, triple: &Triple, _current: bool)82 pub fn legalize_signature(sig: &mut Cow<ir::Signature>, triple: &Triple, _current: bool) {
83     let bits = triple.pointer_width().unwrap().bits();
84 
85     let mut args = Args::new(bits);
86     if let Some(new_params) = legalize_args(&sig.params, &mut args) {
87         sig.to_mut().params = new_params;
88     }
89 }
90 
91 /// Get register class for a type appearing in a legalized signature.
regclass_for_abi_type(ty: ir::Type) -> RegClass92 pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass {
93     if ty.is_int() {
94         GPR
95     } else {
96         match ty.bits() {
97             32 => S,
98             64 => D,
99             128 => Q,
100             _ => panic!("Unexpected {} ABI type for arm32", ty),
101         }
102     }
103 }
104 
105 /// Get the set of allocatable registers for `func`.
allocatable_registers(_func: &ir::Function) -> RegisterSet106 pub fn allocatable_registers(_func: &ir::Function) -> RegisterSet {
107     unimplemented!()
108 }
109