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