1 //! Common helper code for ABI lowering.
2 //!
3 //! This module provides functions and data structures that are useful for implementing the
4 //! `TargetIsa::legalize_signature()` method.
5 
6 use crate::ir::{AbiParam, ArgumentExtension, ArgumentLoc, Type};
7 use alloc::borrow::Cow;
8 use alloc::vec::Vec;
9 use core::cmp::Ordering;
10 
11 /// Legalization action to perform on a single argument or return value when converting a
12 /// signature.
13 ///
14 /// An argument may go through a sequence of legalization steps before it reaches the final
15 /// `Assign` action.
16 #[derive(Clone, Copy, Debug)]
17 pub enum ArgAction {
18     /// Assign the argument to the given location.
19     Assign(ArgumentLoc),
20 
21     /// Assign the argument to the given location and change the type to the specified type.
22     /// This is used by [`ArgumentPurpose::StructArgument`].
23     AssignAndChangeType(ArgumentLoc, Type),
24 
25     /// Convert the argument, then call again.
26     ///
27     /// This action can split an integer type into two smaller integer arguments, or it can split a
28     /// SIMD vector into halves.
29     Convert(ValueConversion),
30 }
31 
32 impl From<ArgumentLoc> for ArgAction {
from(x: ArgumentLoc) -> Self33     fn from(x: ArgumentLoc) -> Self {
34         Self::Assign(x)
35     }
36 }
37 
38 impl From<ValueConversion> for ArgAction {
from(x: ValueConversion) -> Self39     fn from(x: ValueConversion) -> Self {
40         Self::Convert(x)
41     }
42 }
43 
44 /// Legalization action to be applied to a value that is being passed to or from a legalized ABI.
45 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
46 pub enum ValueConversion {
47     /// Split an integer types into low and high parts, using `isplit`.
48     IntSplit,
49 
50     /// Split a vector type into halves with identical lane types, using `vsplit`.
51     VectorSplit,
52 
53     /// Bit-cast to an integer type of the same size.
54     IntBits,
55 
56     /// Sign-extend integer value to the required type.
57     Sext(Type),
58 
59     /// Unsigned zero-extend value to the required type.
60     Uext(Type),
61 
62     /// Pass value by pointer of given integer type.
63     Pointer(Type),
64 }
65 
66 impl ValueConversion {
67     /// Apply this conversion to a type, return the converted type.
apply(self, ty: Type) -> Type68     pub fn apply(self, ty: Type) -> Type {
69         match self {
70             Self::IntSplit => ty.half_width().expect("Integer type too small to split"),
71             Self::VectorSplit => ty.half_vector().expect("Not a vector"),
72             Self::IntBits => Type::int(ty.bits()).expect("Bad integer size"),
73             Self::Sext(nty) | Self::Uext(nty) | Self::Pointer(nty) => nty,
74         }
75     }
76 
77     /// Is this a split conversion that results in two arguments?
is_split(self) -> bool78     pub fn is_split(self) -> bool {
79         match self {
80             Self::IntSplit | Self::VectorSplit => true,
81             _ => false,
82         }
83     }
84 
85     /// Is this a conversion to pointer?
is_pointer(self) -> bool86     pub fn is_pointer(self) -> bool {
87         match self {
88             Self::Pointer(_) => true,
89             _ => false,
90         }
91     }
92 }
93 
94 /// Common trait for assigning arguments to registers or stack locations.
95 ///
96 /// This will be implemented by individual ISAs.
97 pub trait ArgAssigner {
98     /// Pick an assignment action for function argument (or return value) `arg`.
assign(&mut self, arg: &AbiParam) -> ArgAction99     fn assign(&mut self, arg: &AbiParam) -> ArgAction;
100 }
101 
102 /// Legalize the arguments in `args` using the given argument assigner.
103 ///
104 /// This function can be used for both arguments and return values.
legalize_args<AA: ArgAssigner>(args: &[AbiParam], aa: &mut AA) -> Option<Vec<AbiParam>>105 pub fn legalize_args<AA: ArgAssigner>(args: &[AbiParam], aa: &mut AA) -> Option<Vec<AbiParam>> {
106     let mut args = Cow::Borrowed(args);
107 
108     // Iterate over the arguments.
109     // We may need to mutate the vector in place, so don't use a normal iterator, and clone the
110     // argument to avoid holding a reference.
111     let mut argno = 0;
112     while let Some(arg) = args.get(argno).cloned() {
113         // Leave the pre-assigned arguments alone.
114         // We'll assume that they don't interfere with our assignments.
115         if arg.location.is_assigned() {
116             argno += 1;
117             continue;
118         }
119 
120         match aa.assign(&arg) {
121             // Assign argument to a location and move on to the next one.
122             ArgAction::Assign(loc) => {
123                 args.to_mut()[argno].location = loc;
124                 argno += 1;
125             }
126             // Assign argument to a location, change type to the requested one and move on to the
127             // next one.
128             ArgAction::AssignAndChangeType(loc, ty) => {
129                 let arg = &mut args.to_mut()[argno];
130                 arg.location = loc;
131                 arg.value_type = ty;
132                 argno += 1;
133             }
134             // Split this argument into two smaller ones. Then revisit both.
135             ArgAction::Convert(conv) => {
136                 debug_assert!(
137                     !arg.legalized_to_pointer,
138                     "No more conversions allowed after conversion to pointer"
139                 );
140                 let value_type = conv.apply(arg.value_type);
141                 args.to_mut()[argno].value_type = value_type;
142                 if conv.is_pointer() {
143                     args.to_mut()[argno].legalized_to_pointer = true;
144                 } else if conv.is_split() {
145                     let new_arg = AbiParam { value_type, ..arg };
146                     args.to_mut().insert(argno + 1, new_arg);
147                 }
148             }
149         }
150     }
151 
152     match args {
153         Cow::Borrowed(_) => None,
154         Cow::Owned(a) => Some(a),
155     }
156 }
157 
158 /// Determine the right action to take when passing a `have` value type to a call signature where
159 /// the next argument is `arg` which has a different value type.
160 ///
161 /// The signature legalization process in `legalize_args` above can replace a single argument value
162 /// with multiple arguments of smaller types. It can also change the type of an integer argument to
163 /// a larger integer type, requiring the smaller value to be sign- or zero-extended.
164 ///
165 /// The legalizer needs to repair the values at all ABI boundaries:
166 ///
167 /// - Incoming function arguments to the entry block.
168 /// - Function arguments passed to a call.
169 /// - Return values from a call.
170 /// - Return values passed to a return instruction.
171 ///
172 /// The `legalize_abi_value` function helps the legalizer with the process. When the legalizer
173 /// needs to pass a pre-legalized `have` argument, but the ABI argument `arg` has a different value
174 /// type, `legalize_abi_value(have, arg)` tells the legalizer how to create the needed value type
175 /// for the argument.
176 ///
177 /// It may be necessary to call `legalize_abi_value` more than once for a given argument before the
178 /// desired argument type appears. This will happen when a vector or integer type needs to be split
179 /// more than once, for example.
legalize_abi_value(have: Type, arg: &AbiParam) -> ValueConversion180 pub fn legalize_abi_value(have: Type, arg: &AbiParam) -> ValueConversion {
181     let have_bits = have.bits();
182     let arg_bits = arg.value_type.bits();
183 
184     if arg.legalized_to_pointer {
185         return ValueConversion::Pointer(arg.value_type);
186     }
187 
188     match have_bits.cmp(&arg_bits) {
189         // We have fewer bits than the ABI argument.
190         Ordering::Less => {
191             debug_assert!(
192                 have.is_int() && arg.value_type.is_int(),
193                 "Can only extend integer values"
194             );
195             match arg.extension {
196                 ArgumentExtension::Uext => ValueConversion::Uext(arg.value_type),
197                 ArgumentExtension::Sext => ValueConversion::Sext(arg.value_type),
198                 _ => panic!("No argument extension specified"),
199             }
200         }
201         // We have the same number of bits as the argument.
202         Ordering::Equal => {
203             // This must be an integer vector that is split and then extended.
204             debug_assert!(arg.value_type.is_int());
205             debug_assert!(have.is_vector(), "expected vector type, got {}", have);
206             ValueConversion::VectorSplit
207         }
208         // We have more bits than the argument.
209         Ordering::Greater => {
210             if have.is_vector() {
211                 ValueConversion::VectorSplit
212             } else if have.is_float() {
213                 // Convert a float to int so it can be split the next time.
214                 // ARM would do this to pass an `f64` in two registers.
215                 ValueConversion::IntBits
216             } else {
217                 ValueConversion::IntSplit
218             }
219         }
220     }
221 }
222 
223 #[cfg(test)]
224 mod tests {
225     use super::*;
226     use crate::ir::types;
227     use crate::ir::AbiParam;
228 
229     #[test]
legalize()230     fn legalize() {
231         let mut arg = AbiParam::new(types::I32);
232 
233         assert_eq!(
234             legalize_abi_value(types::I64X2, &arg),
235             ValueConversion::VectorSplit
236         );
237         assert_eq!(
238             legalize_abi_value(types::I64, &arg),
239             ValueConversion::IntSplit
240         );
241 
242         // Vector of integers is broken down, then sign-extended.
243         arg.extension = ArgumentExtension::Sext;
244         assert_eq!(
245             legalize_abi_value(types::I16X4, &arg),
246             ValueConversion::VectorSplit
247         );
248         assert_eq!(
249             legalize_abi_value(types::I16.by(2).unwrap(), &arg),
250             ValueConversion::VectorSplit
251         );
252         assert_eq!(
253             legalize_abi_value(types::I16, &arg),
254             ValueConversion::Sext(types::I32)
255         );
256 
257         // 64-bit float is split as an integer.
258         assert_eq!(
259             legalize_abi_value(types::F64, &arg),
260             ValueConversion::IntBits
261         );
262 
263         // Value is passed by reference
264         arg.legalized_to_pointer = true;
265         assert_eq!(
266             legalize_abi_value(types::F64, &arg),
267             ValueConversion::Pointer(types::I32)
268         );
269     }
270 }
271