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 #[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 /// Return an object that can display `self` with correct register names. 54 pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplaySignature<'a> { 55 DisplaySignature(self, regs.into()) 56 } 57 58 /// Find the index of a presumed unique special-purpose parameter. 59 pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> { 60 self.params.iter().rposition(|arg| arg.purpose == purpose) 61 } 62 63 /// Find the index of a presumed unique special-purpose parameter. 64 pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> { 65 self.returns.iter().rposition(|arg| arg.purpose == purpose) 66 } 67 68 /// Does this signature have a parameter whose `ArgumentPurpose` is 69 /// `purpose`? 70 pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool { 71 self.special_param_index(purpose).is_some() 72 } 73 74 /// Does this signature have a return whose `ArgumentPurpose` is `purpose`? 75 pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool { 76 self.special_return_index(purpose).is_some() 77 } 78 79 /// How many special parameters does this function have? 80 pub fn num_special_params(&self) -> usize { 81 self.params 82 .iter() 83 .filter(|p| p.purpose != ArgumentPurpose::Normal) 84 .count() 85 } 86 87 /// How many special returns does this function have? 88 pub fn num_special_returns(&self) -> usize { 89 self.returns 90 .iter() 91 .filter(|r| r.purpose != ArgumentPurpose::Normal) 92 .count() 93 } 94 95 /// Does this signature take an struct return pointer parameter? 96 pub fn uses_struct_return_param(&self) -> bool { 97 self.uses_special_param(ArgumentPurpose::StructReturn) 98 } 99 100 /// Does this return more than one normal value? (Pre-struct return 101 /// legalization) 102 pub fn is_multi_return(&self) -> bool { 103 self.returns 104 .iter() 105 .filter(|r| r.purpose == ArgumentPurpose::Normal) 106 .count() 107 > 1 108 } 109 } 110 111 /// Wrapper type capable of displaying a `Signature` with correct register names. 112 pub struct DisplaySignature<'a>(&'a Signature, Option<&'a RegInfo>); 113 114 fn write_list(f: &mut fmt::Formatter, args: &[AbiParam], regs: Option<&RegInfo>) -> fmt::Result { 115 match args.split_first() { 116 None => {} 117 Some((first, rest)) => { 118 write!(f, "{}", first.display(regs))?; 119 for arg in rest { 120 write!(f, ", {}", arg.display(regs))?; 121 } 122 } 123 } 124 Ok(()) 125 } 126 127 impl<'a> fmt::Display for DisplaySignature<'a> { 128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 129 write!(f, "(")?; 130 write_list(f, &self.0.params, self.1)?; 131 write!(f, ")")?; 132 if !self.0.returns.is_empty() { 133 write!(f, " -> ")?; 134 write_list(f, &self.0.returns, self.1)?; 135 } 136 write!(f, " {}", self.0.call_conv) 137 } 138 } 139 140 impl fmt::Display for Signature { 141 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 142 self.display(None).fmt(f) 143 } 144 } 145 146 /// Function parameter or return value descriptor. 147 /// 148 /// This describes the value type being passed to or from a function along with flags that affect 149 /// how the argument is passed. 150 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 151 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 152 pub struct AbiParam { 153 /// Type of the argument value. 154 pub value_type: Type, 155 /// Special purpose of argument, or `Normal`. 156 pub purpose: ArgumentPurpose, 157 /// Method for extending argument to a full register. 158 pub extension: ArgumentExtension, 159 160 /// ABI-specific location of this argument, or `Unassigned` for arguments that have not yet 161 /// been legalized. 162 pub location: ArgumentLoc, 163 /// Was the argument converted to pointer during legalization? 164 pub legalized_to_pointer: bool, 165 } 166 167 impl AbiParam { 168 /// Create a parameter with default flags. 169 pub fn new(vt: Type) -> Self { 170 Self { 171 value_type: vt, 172 extension: ArgumentExtension::None, 173 purpose: ArgumentPurpose::Normal, 174 location: Default::default(), 175 legalized_to_pointer: false, 176 } 177 } 178 179 /// Create a special-purpose parameter that is not (yet) bound to a specific register. 180 pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self { 181 Self { 182 value_type: vt, 183 extension: ArgumentExtension::None, 184 purpose, 185 location: Default::default(), 186 legalized_to_pointer: false, 187 } 188 } 189 190 /// Create a parameter for a special-purpose register. 191 pub fn special_reg(vt: Type, purpose: ArgumentPurpose, regunit: RegUnit) -> Self { 192 Self { 193 value_type: vt, 194 extension: ArgumentExtension::None, 195 purpose, 196 location: ArgumentLoc::Reg(regunit), 197 legalized_to_pointer: false, 198 } 199 } 200 201 /// Convert `self` to a parameter with the `uext` flag set. 202 pub fn uext(self) -> Self { 203 debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type); 204 Self { 205 extension: ArgumentExtension::Uext, 206 ..self 207 } 208 } 209 210 /// Convert `self` to a parameter type with the `sext` flag set. 211 pub fn sext(self) -> Self { 212 debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type); 213 Self { 214 extension: ArgumentExtension::Sext, 215 ..self 216 } 217 } 218 219 /// Return an object that can display `self` with correct register names. 220 pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplayAbiParam<'a> { 221 DisplayAbiParam(self, regs.into()) 222 } 223 } 224 225 /// Wrapper type capable of displaying a `AbiParam` with correct register names. 226 pub struct DisplayAbiParam<'a>(&'a AbiParam, Option<&'a RegInfo>); 227 228 impl<'a> fmt::Display for DisplayAbiParam<'a> { 229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 230 write!(f, "{}", self.0.value_type)?; 231 if self.0.legalized_to_pointer { 232 write!(f, " ptr")?; 233 } 234 match self.0.extension { 235 ArgumentExtension::None => {} 236 ArgumentExtension::Uext => write!(f, " uext")?, 237 ArgumentExtension::Sext => write!(f, " sext")?, 238 } 239 if self.0.purpose != ArgumentPurpose::Normal { 240 write!(f, " {}", self.0.purpose)?; 241 } 242 243 if self.0.location.is_assigned() { 244 write!(f, " [{}]", self.0.location.display(self.1))?; 245 } 246 247 Ok(()) 248 } 249 } 250 251 impl fmt::Display for AbiParam { 252 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 253 self.display(None).fmt(f) 254 } 255 } 256 257 /// Function argument extension options. 258 /// 259 /// On some architectures, small integer function arguments and/or return values are extended to 260 /// the width of a general-purpose register. 261 /// 262 /// This attribute specifies how an argument or return value should be extended *if the platform 263 /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the 264 /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes 265 /// specify *how* to extend (according to the signedness of the original program) rather than 266 /// *whether* to extend. 267 /// 268 /// For example, on x86-64, the SystemV ABI does not require extensions of narrow values, so these 269 /// `ArgumentExtension` attributes are ignored; but in the Baldrdash (SpiderMonkey) ABI on the same 270 /// platform, all narrow values *are* extended, so these attributes may lead to extra 271 /// zero/sign-extend instructions in the generated machine code. 272 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 273 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 274 pub enum ArgumentExtension { 275 /// No extension, high bits are indeterminate. 276 None, 277 /// Unsigned extension: high bits in register are 0. 278 Uext, 279 /// Signed extension: high bits in register replicate sign bit. 280 Sext, 281 } 282 283 /// The special purpose of a function argument. 284 /// 285 /// Function arguments and return values are used to pass user program values between functions, 286 /// but they are also used to represent special registers with significance to the ABI such as 287 /// frame pointers and callee-saved registers. 288 /// 289 /// The argument purpose is used to indicate any special meaning of an argument or return value. 290 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 291 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 292 pub enum ArgumentPurpose { 293 /// A normal user program value passed to or from a function. 294 Normal, 295 296 /// A C struct passed as argument. 297 StructArgument(u32), 298 299 /// Struct return pointer. 300 /// 301 /// When a function needs to return more data than will fit in registers, the caller passes a 302 /// pointer to a memory location where the return value can be written. In some ABIs, this 303 /// struct return pointer is passed in a specific register. 304 /// 305 /// This argument kind can also appear as a return value for ABIs that require a function with 306 /// a `StructReturn` pointer argument to also return that pointer in a register. 307 StructReturn, 308 309 /// The link register. 310 /// 311 /// Most RISC architectures implement calls by saving the return address in a designated 312 /// register rather than pushing it on the stack. This is represented with a `Link` argument. 313 /// 314 /// Similarly, some return instructions expect the return address in a register represented as 315 /// a `Link` return value. 316 Link, 317 318 /// The frame pointer. 319 /// 320 /// This indicates the frame pointer register which has a special meaning in some ABIs. 321 /// 322 /// The frame pointer appears as an argument and as a return value since it is a callee-saved 323 /// register. 324 FramePointer, 325 326 /// A callee-saved register. 327 /// 328 /// Some calling conventions have registers that must be saved by the callee. These registers 329 /// are represented as `CalleeSaved` arguments and return values. 330 CalleeSaved, 331 332 /// A VM context pointer. 333 /// 334 /// This is a pointer to a context struct containing details about the current sandbox. It is 335 /// used as a base pointer for `vmctx` global values. 336 VMContext, 337 338 /// A signature identifier. 339 /// 340 /// This is a special-purpose argument used to identify the calling convention expected by the 341 /// caller in an indirect call. The callee can verify that the expected signature ID matches. 342 SignatureId, 343 344 /// A stack limit pointer. 345 /// 346 /// This is a pointer to a stack limit. It is used to check the current stack pointer 347 /// against. Can only appear once in a signature. 348 StackLimit, 349 350 /// A callee TLS value. 351 /// 352 /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the 353 /// TLS-register values for the caller and the callee. This argument is used to provide the 354 /// value for the callee. 355 CalleeTLS, 356 357 /// A caller TLS value. 358 /// 359 /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the 360 /// TLS-register values for the caller and the callee. This argument is used to provide the 361 /// value for the caller. 362 CallerTLS, 363 } 364 365 impl fmt::Display for ArgumentPurpose { 366 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 367 f.write_str(match self { 368 Self::Normal => "normal", 369 Self::StructArgument(size) => return write!(f, "sarg({})", size), 370 Self::StructReturn => "sret", 371 Self::Link => "link", 372 Self::FramePointer => "fp", 373 Self::CalleeSaved => "csr", 374 Self::VMContext => "vmctx", 375 Self::SignatureId => "sigid", 376 Self::StackLimit => "stack_limit", 377 Self::CalleeTLS => "callee_tls", 378 Self::CallerTLS => "caller_tls", 379 }) 380 } 381 } 382 383 impl FromStr for ArgumentPurpose { 384 type Err = (); 385 fn from_str(s: &str) -> Result<Self, ()> { 386 match s { 387 "normal" => Ok(Self::Normal), 388 "sret" => Ok(Self::StructReturn), 389 "link" => Ok(Self::Link), 390 "fp" => Ok(Self::FramePointer), 391 "csr" => Ok(Self::CalleeSaved), 392 "vmctx" => Ok(Self::VMContext), 393 "sigid" => Ok(Self::SignatureId), 394 "stack_limit" => Ok(Self::StackLimit), 395 _ if s.starts_with("sarg(") => { 396 if !s.ends_with(")") { 397 return Err(()); 398 } 399 // Parse 'sarg(size)' 400 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?; 401 Ok(Self::StructArgument(size)) 402 } 403 _ => Err(()), 404 } 405 } 406 } 407 408 /// An external function. 409 /// 410 /// Information about a function that can be called directly with a direct `call` instruction. 411 #[derive(Clone, Debug)] 412 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 413 pub struct ExtFuncData { 414 /// Name of the external function. 415 pub name: ExternalName, 416 /// Call signature of function. 417 pub signature: SigRef, 418 /// Will this function be defined nearby, such that it will always be a certain distance away, 419 /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that 420 /// symbols meant to be preemptible cannot be considered colocated. 421 /// 422 /// If `true`, some backends may use relocation forms that have limited range. The exact 423 /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift 424 /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how 425 /// far away the target will be, it is best not to set the `colocated` flag; in general, this 426 /// flag is best used when the target is known to be in the same unit of code generation, such 427 /// as a Wasm module. 428 /// 429 /// See the documentation for [`RelocDistance`](crate::machinst::RelocDistance) for more details. A 430 /// `colocated` flag value of `true` implies `RelocDistance::Near`. 431 pub colocated: bool, 432 } 433 434 impl fmt::Display for ExtFuncData { 435 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 436 if self.colocated { 437 write!(f, "colocated ")?; 438 } 439 write!(f, "{} {}", self.name, self.signature) 440 } 441 } 442 443 impl ExtFuncData { 444 /// Return an estimate of the distance to the referred-to function symbol. 445 pub fn reloc_distance(&self) -> RelocDistance { 446 if self.colocated { 447 RelocDistance::Near 448 } else { 449 RelocDistance::Far 450 } 451 } 452 } 453 454 #[cfg(test)] 455 mod tests { 456 use super::*; 457 use crate::ir::types::{B8, F32, I32}; 458 use alloc::string::ToString; 459 460 #[test] 461 fn argument_type() { 462 let t = AbiParam::new(I32); 463 assert_eq!(t.to_string(), "i32"); 464 let mut t = t.uext(); 465 assert_eq!(t.to_string(), "i32 uext"); 466 assert_eq!(t.sext().to_string(), "i32 sext"); 467 t.purpose = ArgumentPurpose::StructReturn; 468 assert_eq!(t.to_string(), "i32 uext sret"); 469 t.legalized_to_pointer = true; 470 assert_eq!(t.to_string(), "i32 ptr uext sret"); 471 } 472 473 #[test] 474 fn argument_purpose() { 475 let all_purpose = [ 476 (ArgumentPurpose::Normal, "normal"), 477 (ArgumentPurpose::StructReturn, "sret"), 478 (ArgumentPurpose::Link, "link"), 479 (ArgumentPurpose::FramePointer, "fp"), 480 (ArgumentPurpose::CalleeSaved, "csr"), 481 (ArgumentPurpose::VMContext, "vmctx"), 482 (ArgumentPurpose::SignatureId, "sigid"), 483 (ArgumentPurpose::StackLimit, "stack_limit"), 484 (ArgumentPurpose::StructArgument(42), "sarg(42)"), 485 ]; 486 for &(e, n) in &all_purpose { 487 assert_eq!(e.to_string(), n); 488 assert_eq!(Ok(e), n.parse()); 489 } 490 } 491 492 #[test] 493 fn call_conv() { 494 for &cc in &[ 495 CallConv::Fast, 496 CallConv::Cold, 497 CallConv::SystemV, 498 CallConv::WindowsFastcall, 499 CallConv::BaldrdashSystemV, 500 CallConv::BaldrdashWindows, 501 CallConv::Baldrdash2020, 502 ] { 503 assert_eq!(Ok(cc), cc.to_string().parse()) 504 } 505 } 506 507 #[test] 508 fn signatures() { 509 let mut sig = Signature::new(CallConv::BaldrdashSystemV); 510 assert_eq!(sig.to_string(), "() baldrdash_system_v"); 511 sig.params.push(AbiParam::new(I32)); 512 assert_eq!(sig.to_string(), "(i32) baldrdash_system_v"); 513 sig.returns.push(AbiParam::new(F32)); 514 assert_eq!(sig.to_string(), "(i32) -> f32 baldrdash_system_v"); 515 sig.params.push(AbiParam::new(I32.by(4).unwrap())); 516 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 baldrdash_system_v"); 517 sig.returns.push(AbiParam::new(B8)); 518 assert_eq!( 519 sig.to_string(), 520 "(i32, i32x4) -> f32, b8 baldrdash_system_v" 521 ); 522 523 // Order does not matter. 524 sig.params[0].location = ArgumentLoc::Stack(24); 525 sig.params[1].location = ArgumentLoc::Stack(8); 526 527 // Writing ABI-annotated signatures. 528 assert_eq!( 529 sig.to_string(), 530 "(i32 [24], i32x4 [8]) -> f32, b8 baldrdash_system_v" 531 ); 532 } 533 } 534