1 //! External function calls. 2 //! 3 //! To a Cranelift function, all functions are "external". Directly called functions must be 4 //! declared in the preamble, and all function calls must have a signature. 5 //! 6 //! This module declares the data types used to represent external functions and call signatures. 7 8 use crate::ir::{ExternalName, SigRef, Type}; 9 use crate::isa::CallConv; 10 use crate::machinst::RelocDistance; 11 use alloc::vec::Vec; 12 use core::fmt; 13 use core::str::FromStr; 14 #[cfg(feature = "enable-serde")] 15 use serde::{Deserialize, Serialize}; 16 17 /// Function signature. 18 /// 19 /// The function signature describes the types of formal parameters and return values along with 20 /// other details that are needed to call a function correctly. 21 /// 22 /// A signature can optionally include ISA-specific ABI information which specifies exactly how 23 /// arguments and return values are passed. 24 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 25 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 26 pub struct Signature { 27 /// The arguments passed to the function. 28 pub params: Vec<AbiParam>, 29 /// Values returned from the function. 30 pub returns: Vec<AbiParam>, 31 32 /// Calling convention. 33 pub call_conv: CallConv, 34 } 35 36 impl Signature { 37 /// Create a new blank signature. 38 pub fn new(call_conv: CallConv) -> Self { 39 Self { 40 params: Vec::new(), 41 returns: Vec::new(), 42 call_conv, 43 } 44 } 45 46 /// Clear the signature so it is identical to a fresh one returned by `new()`. 47 pub fn clear(&mut self, call_conv: CallConv) { 48 self.params.clear(); 49 self.returns.clear(); 50 self.call_conv = call_conv; 51 } 52 53 /// Find the index of a presumed unique special-purpose parameter. 54 pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> { 55 self.params.iter().rposition(|arg| arg.purpose == purpose) 56 } 57 58 /// Find the index of a presumed unique special-purpose parameter. 59 pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> { 60 self.returns.iter().rposition(|arg| arg.purpose == purpose) 61 } 62 63 /// Does this signature have a parameter whose `ArgumentPurpose` is 64 /// `purpose`? 65 pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool { 66 self.special_param_index(purpose).is_some() 67 } 68 69 /// Does this signature have a return whose `ArgumentPurpose` is `purpose`? 70 pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool { 71 self.special_return_index(purpose).is_some() 72 } 73 74 /// How many special parameters does this function have? 75 pub fn num_special_params(&self) -> usize { 76 self.params 77 .iter() 78 .filter(|p| p.purpose != ArgumentPurpose::Normal) 79 .count() 80 } 81 82 /// How many special returns does this function have? 83 pub fn num_special_returns(&self) -> usize { 84 self.returns 85 .iter() 86 .filter(|r| r.purpose != ArgumentPurpose::Normal) 87 .count() 88 } 89 90 /// Does this signature take an struct return pointer parameter? 91 pub fn uses_struct_return_param(&self) -> bool { 92 self.uses_special_param(ArgumentPurpose::StructReturn) 93 } 94 95 /// Does this return more than one normal value? (Pre-struct return 96 /// legalization) 97 pub fn is_multi_return(&self) -> bool { 98 self.returns 99 .iter() 100 .filter(|r| r.purpose == ArgumentPurpose::Normal) 101 .count() 102 > 1 103 } 104 } 105 106 fn write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result { 107 match args.split_first() { 108 None => {} 109 Some((first, rest)) => { 110 write!(f, "{}", first)?; 111 for arg in rest { 112 write!(f, ", {}", arg)?; 113 } 114 } 115 } 116 Ok(()) 117 } 118 119 impl fmt::Display for Signature { 120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 121 write!(f, "(")?; 122 write_list(f, &self.params)?; 123 write!(f, ")")?; 124 if !self.returns.is_empty() { 125 write!(f, " -> ")?; 126 write_list(f, &self.returns)?; 127 } 128 write!(f, " {}", self.call_conv) 129 } 130 } 131 132 /// Function parameter or return value descriptor. 133 /// 134 /// This describes the value type being passed to or from a function along with flags that affect 135 /// how the argument is passed. 136 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 137 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 138 pub struct AbiParam { 139 /// Type of the argument value. 140 pub value_type: Type, 141 /// Special purpose of argument, or `Normal`. 142 pub purpose: ArgumentPurpose, 143 /// Method for extending argument to a full register. 144 pub extension: ArgumentExtension, 145 } 146 147 impl AbiParam { 148 /// Create a parameter with default flags. 149 pub fn new(vt: Type) -> Self { 150 Self { 151 value_type: vt, 152 extension: ArgumentExtension::None, 153 purpose: ArgumentPurpose::Normal, 154 } 155 } 156 157 /// Create a special-purpose parameter that is not (yet) bound to a specific register. 158 pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self { 159 Self { 160 value_type: vt, 161 extension: ArgumentExtension::None, 162 purpose, 163 } 164 } 165 166 /// Convert `self` to a parameter with the `uext` flag set. 167 pub fn uext(self) -> Self { 168 debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type); 169 Self { 170 extension: ArgumentExtension::Uext, 171 ..self 172 } 173 } 174 175 /// Convert `self` to a parameter type with the `sext` flag set. 176 pub fn sext(self) -> Self { 177 debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type); 178 Self { 179 extension: ArgumentExtension::Sext, 180 ..self 181 } 182 } 183 } 184 185 impl fmt::Display for AbiParam { 186 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 187 write!(f, "{}", self.value_type)?; 188 match self.extension { 189 ArgumentExtension::None => {} 190 ArgumentExtension::Uext => write!(f, " uext")?, 191 ArgumentExtension::Sext => write!(f, " sext")?, 192 } 193 if self.purpose != ArgumentPurpose::Normal { 194 write!(f, " {}", self.purpose)?; 195 } 196 Ok(()) 197 } 198 } 199 200 /// Function argument extension options. 201 /// 202 /// On some architectures, small integer function arguments and/or return values are extended to 203 /// the width of a general-purpose register. 204 /// 205 /// This attribute specifies how an argument or return value should be extended *if the platform 206 /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the 207 /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes 208 /// specify *how* to extend (according to the signedness of the original program) rather than 209 /// *whether* to extend. 210 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 211 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 212 pub enum ArgumentExtension { 213 /// No extension, high bits are indeterminate. 214 None, 215 /// Unsigned extension: high bits in register are 0. 216 Uext, 217 /// Signed extension: high bits in register replicate sign bit. 218 Sext, 219 } 220 221 /// The special purpose of a function argument. 222 /// 223 /// Function arguments and return values are used to pass user program values between functions, 224 /// but they are also used to represent special registers with significance to the ABI such as 225 /// frame pointers and callee-saved registers. 226 /// 227 /// The argument purpose is used to indicate any special meaning of an argument or return value. 228 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 229 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 230 pub enum ArgumentPurpose { 231 /// A normal user program value passed to or from a function. 232 Normal, 233 234 /// A C struct passed as argument. 235 StructArgument(u32), 236 237 /// Struct return pointer. 238 /// 239 /// When a function needs to return more data than will fit in registers, the caller passes a 240 /// pointer to a memory location where the return value can be written. In some ABIs, this 241 /// struct return pointer is passed in a specific register. 242 /// 243 /// This argument kind can also appear as a return value for ABIs that require a function with 244 /// a `StructReturn` pointer argument to also return that pointer in a register. 245 StructReturn, 246 247 /// A VM context pointer. 248 /// 249 /// This is a pointer to a context struct containing details about the current sandbox. It is 250 /// used as a base pointer for `vmctx` global values. 251 VMContext, 252 253 /// A signature identifier. 254 /// 255 /// This is a special-purpose argument used to identify the calling convention expected by the 256 /// caller in an indirect call. The callee can verify that the expected signature ID matches. 257 SignatureId, 258 259 /// A stack limit pointer. 260 /// 261 /// This is a pointer to a stack limit. It is used to check the current stack pointer 262 /// against. Can only appear once in a signature. 263 StackLimit, 264 } 265 266 impl fmt::Display for ArgumentPurpose { 267 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 268 f.write_str(match self { 269 Self::Normal => "normal", 270 Self::StructArgument(size) => return write!(f, "sarg({})", size), 271 Self::StructReturn => "sret", 272 Self::VMContext => "vmctx", 273 Self::SignatureId => "sigid", 274 Self::StackLimit => "stack_limit", 275 }) 276 } 277 } 278 279 impl FromStr for ArgumentPurpose { 280 type Err = (); 281 fn from_str(s: &str) -> Result<Self, ()> { 282 match s { 283 "normal" => Ok(Self::Normal), 284 "sret" => Ok(Self::StructReturn), 285 "vmctx" => Ok(Self::VMContext), 286 "sigid" => Ok(Self::SignatureId), 287 "stack_limit" => Ok(Self::StackLimit), 288 _ if s.starts_with("sarg(") => { 289 if !s.ends_with(")") { 290 return Err(()); 291 } 292 // Parse 'sarg(size)' 293 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?; 294 Ok(Self::StructArgument(size)) 295 } 296 _ => Err(()), 297 } 298 } 299 } 300 301 /// An external function. 302 /// 303 /// Information about a function that can be called directly with a direct `call` instruction. 304 #[derive(Clone, Debug)] 305 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 306 pub struct ExtFuncData { 307 /// Name of the external function. 308 pub name: ExternalName, 309 /// Call signature of function. 310 pub signature: SigRef, 311 /// Will this function be defined nearby, such that it will always be a certain distance away, 312 /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that 313 /// symbols meant to be preemptible cannot be considered colocated. 314 /// 315 /// If `true`, some backends may use relocation forms that have limited range. The exact 316 /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift 317 /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how 318 /// far away the target will be, it is best not to set the `colocated` flag; in general, this 319 /// flag is best used when the target is known to be in the same unit of code generation, such 320 /// as a Wasm module. 321 /// 322 /// See the documentation for [`RelocDistance`](crate::machinst::RelocDistance) for more details. A 323 /// `colocated` flag value of `true` implies `RelocDistance::Near`. 324 pub colocated: bool, 325 } 326 327 impl fmt::Display for ExtFuncData { 328 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 329 if self.colocated { 330 write!(f, "colocated ")?; 331 } 332 write!(f, "{} {}", self.name, self.signature) 333 } 334 } 335 336 impl ExtFuncData { 337 /// Return an estimate of the distance to the referred-to function symbol. 338 pub fn reloc_distance(&self) -> RelocDistance { 339 if self.colocated { 340 RelocDistance::Near 341 } else { 342 RelocDistance::Far 343 } 344 } 345 } 346 347 #[cfg(test)] 348 mod tests { 349 use super::*; 350 use crate::ir::types::{B8, F32, I32}; 351 use alloc::string::ToString; 352 353 #[test] 354 fn argument_type() { 355 let t = AbiParam::new(I32); 356 assert_eq!(t.to_string(), "i32"); 357 let mut t = t.uext(); 358 assert_eq!(t.to_string(), "i32 uext"); 359 assert_eq!(t.sext().to_string(), "i32 sext"); 360 t.purpose = ArgumentPurpose::StructReturn; 361 assert_eq!(t.to_string(), "i32 uext sret"); 362 } 363 364 #[test] 365 fn argument_purpose() { 366 let all_purpose = [ 367 (ArgumentPurpose::Normal, "normal"), 368 (ArgumentPurpose::StructReturn, "sret"), 369 (ArgumentPurpose::VMContext, "vmctx"), 370 (ArgumentPurpose::SignatureId, "sigid"), 371 (ArgumentPurpose::StackLimit, "stack_limit"), 372 (ArgumentPurpose::StructArgument(42), "sarg(42)"), 373 ]; 374 for &(e, n) in &all_purpose { 375 assert_eq!(e.to_string(), n); 376 assert_eq!(Ok(e), n.parse()); 377 } 378 } 379 380 #[test] 381 fn call_conv() { 382 for &cc in &[ 383 CallConv::Fast, 384 CallConv::Cold, 385 CallConv::SystemV, 386 CallConv::WindowsFastcall, 387 ] { 388 assert_eq!(Ok(cc), cc.to_string().parse()) 389 } 390 } 391 392 #[test] 393 fn signatures() { 394 let mut sig = Signature::new(CallConv::WindowsFastcall); 395 assert_eq!(sig.to_string(), "() windows_fastcall"); 396 sig.params.push(AbiParam::new(I32)); 397 assert_eq!(sig.to_string(), "(i32) windows_fastcall"); 398 sig.returns.push(AbiParam::new(F32)); 399 assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall"); 400 sig.params.push(AbiParam::new(I32.by(4).unwrap())); 401 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall"); 402 sig.returns.push(AbiParam::new(B8)); 403 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8 windows_fastcall"); 404 } 405 } 406