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::{ArgumentLoc, ExternalName, SigRef, Type}; 9 use crate::isa::{CallConv, RegInfo, RegUnit}; 10 use crate::machinst::RelocDistance; 11 use alloc::vec::Vec; 12 use core::fmt; 13 use core::str::FromStr; 14 15 /// Function signature. 16 /// 17 /// The function signature describes the types of formal parameters and return values along with 18 /// other details that are needed to call a function correctly. 19 /// 20 /// A signature can optionally include ISA-specific ABI information which specifies exactly how 21 /// arguments and return values are passed. 22 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 23 pub struct Signature { 24 /// The arguments passed to the function. 25 pub params: Vec<AbiParam>, 26 /// Values returned from the function. 27 pub returns: Vec<AbiParam>, 28 29 /// Calling convention. 30 pub call_conv: CallConv, 31 } 32 33 impl Signature { 34 /// Create a new blank signature. 35 pub fn new(call_conv: CallConv) -> Self { 36 Self { 37 params: Vec::new(), 38 returns: Vec::new(), 39 call_conv, 40 } 41 } 42 43 /// Clear the signature so it is identical to a fresh one returned by `new()`. 44 pub fn clear(&mut self, call_conv: CallConv) { 45 self.params.clear(); 46 self.returns.clear(); 47 self.call_conv = call_conv; 48 } 49 50 /// Return an object that can display `self` with correct register names. 51 pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplaySignature<'a> { 52 DisplaySignature(self, regs.into()) 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 /// Wrapper type capable of displaying a `Signature` with correct register names. 109 pub struct DisplaySignature<'a>(&'a Signature, Option<&'a RegInfo>); 110 111 fn write_list(f: &mut fmt::Formatter, args: &[AbiParam], regs: Option<&RegInfo>) -> fmt::Result { 112 match args.split_first() { 113 None => {} 114 Some((first, rest)) => { 115 write!(f, "{}", first.display(regs))?; 116 for arg in rest { 117 write!(f, ", {}", arg.display(regs))?; 118 } 119 } 120 } 121 Ok(()) 122 } 123 124 impl<'a> fmt::Display for DisplaySignature<'a> { 125 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 126 write!(f, "(")?; 127 write_list(f, &self.0.params, self.1)?; 128 write!(f, ")")?; 129 if !self.0.returns.is_empty() { 130 write!(f, " -> ")?; 131 write_list(f, &self.0.returns, self.1)?; 132 } 133 write!(f, " {}", self.0.call_conv) 134 } 135 } 136 137 impl fmt::Display for Signature { 138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 139 self.display(None).fmt(f) 140 } 141 } 142 143 /// Function parameter or return value descriptor. 144 /// 145 /// This describes the value type being passed to or from a function along with flags that affect 146 /// how the argument is passed. 147 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 148 pub struct AbiParam { 149 /// Type of the argument value. 150 pub value_type: Type, 151 /// Special purpose of argument, or `Normal`. 152 pub purpose: ArgumentPurpose, 153 /// Method for extending argument to a full register. 154 pub extension: ArgumentExtension, 155 156 /// ABI-specific location of this argument, or `Unassigned` for arguments that have not yet 157 /// been legalized. 158 pub location: ArgumentLoc, 159 } 160 161 impl AbiParam { 162 /// Create a parameter with default flags. 163 pub fn new(vt: Type) -> Self { 164 Self { 165 value_type: vt, 166 extension: ArgumentExtension::None, 167 purpose: ArgumentPurpose::Normal, 168 location: Default::default(), 169 } 170 } 171 172 /// Create a special-purpose parameter that is not (yet) bound to a specific register. 173 pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self { 174 Self { 175 value_type: vt, 176 extension: ArgumentExtension::None, 177 purpose, 178 location: Default::default(), 179 } 180 } 181 182 /// Create a parameter for a special-purpose register. 183 pub fn special_reg(vt: Type, purpose: ArgumentPurpose, regunit: RegUnit) -> Self { 184 Self { 185 value_type: vt, 186 extension: ArgumentExtension::None, 187 purpose, 188 location: ArgumentLoc::Reg(regunit), 189 } 190 } 191 192 /// Convert `self` to a parameter with the `uext` flag set. 193 pub fn uext(self) -> Self { 194 debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type); 195 Self { 196 extension: ArgumentExtension::Uext, 197 ..self 198 } 199 } 200 201 /// Convert `self` to a parameter type with the `sext` flag set. 202 pub fn sext(self) -> Self { 203 debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type); 204 Self { 205 extension: ArgumentExtension::Sext, 206 ..self 207 } 208 } 209 210 /// Return an object that can display `self` with correct register names. 211 pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplayAbiParam<'a> { 212 DisplayAbiParam(self, regs.into()) 213 } 214 } 215 216 /// Wrapper type capable of displaying a `AbiParam` with correct register names. 217 pub struct DisplayAbiParam<'a>(&'a AbiParam, Option<&'a RegInfo>); 218 219 impl<'a> fmt::Display for DisplayAbiParam<'a> { 220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 221 write!(f, "{}", self.0.value_type)?; 222 match self.0.extension { 223 ArgumentExtension::None => {} 224 ArgumentExtension::Uext => write!(f, " uext")?, 225 ArgumentExtension::Sext => write!(f, " sext")?, 226 } 227 if self.0.purpose != ArgumentPurpose::Normal { 228 write!(f, " {}", self.0.purpose)?; 229 } 230 231 if self.0.location.is_assigned() { 232 write!(f, " [{}]", self.0.location.display(self.1))?; 233 } 234 235 Ok(()) 236 } 237 } 238 239 impl fmt::Display for AbiParam { 240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 241 self.display(None).fmt(f) 242 } 243 } 244 245 /// Function argument extension options. 246 /// 247 /// On some architectures, small integer function arguments are extended to the width of a 248 /// general-purpose register. 249 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 250 pub enum ArgumentExtension { 251 /// No extension, high bits are indeterminate. 252 None, 253 /// Unsigned extension: high bits in register are 0. 254 Uext, 255 /// Signed extension: high bits in register replicate sign bit. 256 Sext, 257 } 258 259 /// The special purpose of a function argument. 260 /// 261 /// Function arguments and return values are used to pass user program values between functions, 262 /// but they are also used to represent special registers with significance to the ABI such as 263 /// frame pointers and callee-saved registers. 264 /// 265 /// The argument purpose is used to indicate any special meaning of an argument or return value. 266 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 267 pub enum ArgumentPurpose { 268 /// A normal user program value passed to or from a function. 269 Normal, 270 271 /// Struct return pointer. 272 /// 273 /// When a function needs to return more data than will fit in registers, the caller passes a 274 /// pointer to a memory location where the return value can be written. In some ABIs, this 275 /// struct return pointer is passed in a specific register. 276 /// 277 /// This argument kind can also appear as a return value for ABIs that require a function with 278 /// a `StructReturn` pointer argument to also return that pointer in a register. 279 StructReturn, 280 281 /// The link register. 282 /// 283 /// Most RISC architectures implement calls by saving the return address in a designated 284 /// register rather than pushing it on the stack. This is represented with a `Link` argument. 285 /// 286 /// Similarly, some return instructions expect the return address in a register represented as 287 /// a `Link` return value. 288 Link, 289 290 /// The frame pointer. 291 /// 292 /// This indicates the frame pointer register which has a special meaning in some ABIs. 293 /// 294 /// The frame pointer appears as an argument and as a return value since it is a callee-saved 295 /// register. 296 FramePointer, 297 298 /// A callee-saved register. 299 /// 300 /// Some calling conventions have registers that must be saved by the callee. These registers 301 /// are represented as `CalleeSaved` arguments and return values. 302 CalleeSaved, 303 304 /// A VM context pointer. 305 /// 306 /// This is a pointer to a context struct containing details about the current sandbox. It is 307 /// used as a base pointer for `vmctx` global values. 308 VMContext, 309 310 /// A signature identifier. 311 /// 312 /// This is a special-purpose argument used to identify the calling convention expected by the 313 /// caller in an indirect call. The callee can verify that the expected signature ID matches. 314 SignatureId, 315 316 /// A stack limit pointer. 317 /// 318 /// This is a pointer to a stack limit. It is used to check the current stack pointer 319 /// against. Can only appear once in a signature. 320 StackLimit, 321 } 322 323 /// Text format names of the `ArgumentPurpose` variants. 324 static PURPOSE_NAMES: [&str; 8] = [ 325 "normal", 326 "sret", 327 "link", 328 "fp", 329 "csr", 330 "vmctx", 331 "sigid", 332 "stack_limit", 333 ]; 334 335 impl fmt::Display for ArgumentPurpose { 336 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 337 f.write_str(PURPOSE_NAMES[*self as usize]) 338 } 339 } 340 341 impl FromStr for ArgumentPurpose { 342 type Err = (); 343 fn from_str(s: &str) -> Result<Self, ()> { 344 match s { 345 "normal" => Ok(Self::Normal), 346 "sret" => Ok(Self::StructReturn), 347 "link" => Ok(Self::Link), 348 "fp" => Ok(Self::FramePointer), 349 "csr" => Ok(Self::CalleeSaved), 350 "vmctx" => Ok(Self::VMContext), 351 "sigid" => Ok(Self::SignatureId), 352 "stack_limit" => Ok(Self::StackLimit), 353 _ => Err(()), 354 } 355 } 356 } 357 358 /// An external function. 359 /// 360 /// Information about a function that can be called directly with a direct `call` instruction. 361 #[derive(Clone, Debug)] 362 pub struct ExtFuncData { 363 /// Name of the external function. 364 pub name: ExternalName, 365 /// Call signature of function. 366 pub signature: SigRef, 367 /// Will this function be defined nearby, such that it will always be a certain distance away, 368 /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that 369 /// symbols meant to be preemptible cannot be considered colocated. 370 /// 371 /// If `true`, some backends may use relocation forms that have limited range. The exact 372 /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift 373 /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how 374 /// far away the target will be, it is best not to set the `colocated` flag; in general, this 375 /// flag is best used when the target is known to be in the same unit of code generation, such 376 /// as a Wasm module. 377 /// 378 /// See the documentation for [`RelocDistance`](machinst::RelocDistance) for more details. A 379 /// `colocated` flag value of `true` implies `RelocDistance::Near`. 380 pub colocated: bool, 381 } 382 383 impl fmt::Display for ExtFuncData { 384 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 385 if self.colocated { 386 write!(f, "colocated ")?; 387 } 388 write!(f, "{} {}", self.name, self.signature) 389 } 390 } 391 392 impl ExtFuncData { 393 /// Return an estimate of the distance to the referred-to function symbol. 394 pub fn reloc_distance(&self) -> RelocDistance { 395 if self.colocated { 396 RelocDistance::Near 397 } else { 398 RelocDistance::Far 399 } 400 } 401 } 402 403 #[cfg(test)] 404 mod tests { 405 use super::*; 406 use crate::ir::types::{B8, F32, I32}; 407 use alloc::string::ToString; 408 409 #[test] 410 fn argument_type() { 411 let t = AbiParam::new(I32); 412 assert_eq!(t.to_string(), "i32"); 413 let mut t = t.uext(); 414 assert_eq!(t.to_string(), "i32 uext"); 415 assert_eq!(t.sext().to_string(), "i32 sext"); 416 t.purpose = ArgumentPurpose::StructReturn; 417 assert_eq!(t.to_string(), "i32 uext sret"); 418 } 419 420 #[test] 421 fn argument_purpose() { 422 let all_purpose = [ 423 ArgumentPurpose::Normal, 424 ArgumentPurpose::StructReturn, 425 ArgumentPurpose::Link, 426 ArgumentPurpose::FramePointer, 427 ArgumentPurpose::CalleeSaved, 428 ArgumentPurpose::VMContext, 429 ArgumentPurpose::SignatureId, 430 ArgumentPurpose::StackLimit, 431 ]; 432 for (&e, &n) in all_purpose.iter().zip(PURPOSE_NAMES.iter()) { 433 assert_eq!(e.to_string(), n); 434 assert_eq!(Ok(e), n.parse()); 435 } 436 } 437 438 #[test] 439 fn call_conv() { 440 for &cc in &[ 441 CallConv::Fast, 442 CallConv::Cold, 443 CallConv::SystemV, 444 CallConv::WindowsFastcall, 445 CallConv::BaldrdashSystemV, 446 CallConv::BaldrdashWindows, 447 ] { 448 assert_eq!(Ok(cc), cc.to_string().parse()) 449 } 450 } 451 452 #[test] 453 fn signatures() { 454 let mut sig = Signature::new(CallConv::BaldrdashSystemV); 455 assert_eq!(sig.to_string(), "() baldrdash_system_v"); 456 sig.params.push(AbiParam::new(I32)); 457 assert_eq!(sig.to_string(), "(i32) baldrdash_system_v"); 458 sig.returns.push(AbiParam::new(F32)); 459 assert_eq!(sig.to_string(), "(i32) -> f32 baldrdash_system_v"); 460 sig.params.push(AbiParam::new(I32.by(4).unwrap())); 461 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 baldrdash_system_v"); 462 sig.returns.push(AbiParam::new(B8)); 463 assert_eq!( 464 sig.to_string(), 465 "(i32, i32x4) -> f32, b8 baldrdash_system_v" 466 ); 467 468 // Order does not matter. 469 sig.params[0].location = ArgumentLoc::Stack(24); 470 sig.params[1].location = ArgumentLoc::Stack(8); 471 472 // Writing ABI-annotated signatures. 473 assert_eq!( 474 sig.to_string(), 475 "(i32 [24], i32x4 [8]) -> f32, b8 baldrdash_system_v" 476 ); 477 } 478 } 479