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