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 /// Was the argument converted to pointer during legalization? 147 pub legalized_to_pointer: bool, 148 } 149 150 impl AbiParam { 151 /// Create a parameter with default flags. 152 pub fn new(vt: Type) -> Self { 153 Self { 154 value_type: vt, 155 extension: ArgumentExtension::None, 156 purpose: ArgumentPurpose::Normal, 157 legalized_to_pointer: false, 158 } 159 } 160 161 /// Create a special-purpose parameter that is not (yet) bound to a specific register. 162 pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self { 163 Self { 164 value_type: vt, 165 extension: ArgumentExtension::None, 166 purpose, 167 legalized_to_pointer: false, 168 } 169 } 170 171 /// Convert `self` to a parameter with the `uext` flag set. 172 pub fn uext(self) -> Self { 173 debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type); 174 Self { 175 extension: ArgumentExtension::Uext, 176 ..self 177 } 178 } 179 180 /// Convert `self` to a parameter type with the `sext` flag set. 181 pub fn sext(self) -> Self { 182 debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type); 183 Self { 184 extension: ArgumentExtension::Sext, 185 ..self 186 } 187 } 188 } 189 190 impl fmt::Display for AbiParam { 191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 192 write!(f, "{}", self.value_type)?; 193 if self.legalized_to_pointer { 194 write!(f, " ptr")?; 195 } 196 match self.extension { 197 ArgumentExtension::None => {} 198 ArgumentExtension::Uext => write!(f, " uext")?, 199 ArgumentExtension::Sext => write!(f, " sext")?, 200 } 201 if self.purpose != ArgumentPurpose::Normal { 202 write!(f, " {}", self.purpose)?; 203 } 204 Ok(()) 205 } 206 } 207 208 /// Function argument extension options. 209 /// 210 /// On some architectures, small integer function arguments and/or return values are extended to 211 /// the width of a general-purpose register. 212 /// 213 /// This attribute specifies how an argument or return value should be extended *if the platform 214 /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the 215 /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes 216 /// specify *how* to extend (according to the signedness of the original program) rather than 217 /// *whether* to extend. 218 /// 219 /// For example, on x86-64, the SystemV ABI does not require extensions of narrow values, so these 220 /// `ArgumentExtension` attributes are ignored; but in the Baldrdash (SpiderMonkey) ABI on the same 221 /// platform, all narrow values *are* extended, so these attributes may lead to extra 222 /// zero/sign-extend instructions in the generated machine code. 223 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 224 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 225 pub enum ArgumentExtension { 226 /// No extension, high bits are indeterminate. 227 None, 228 /// Unsigned extension: high bits in register are 0. 229 Uext, 230 /// Signed extension: high bits in register replicate sign bit. 231 Sext, 232 } 233 234 /// The special purpose of a function argument. 235 /// 236 /// Function arguments and return values are used to pass user program values between functions, 237 /// but they are also used to represent special registers with significance to the ABI such as 238 /// frame pointers and callee-saved registers. 239 /// 240 /// The argument purpose is used to indicate any special meaning of an argument or return value. 241 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 242 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 243 pub enum ArgumentPurpose { 244 /// A normal user program value passed to or from a function. 245 Normal, 246 247 /// A C struct passed as argument. 248 StructArgument(u32), 249 250 /// Struct return pointer. 251 /// 252 /// When a function needs to return more data than will fit in registers, the caller passes a 253 /// pointer to a memory location where the return value can be written. In some ABIs, this 254 /// struct return pointer is passed in a specific register. 255 /// 256 /// This argument kind can also appear as a return value for ABIs that require a function with 257 /// a `StructReturn` pointer argument to also return that pointer in a register. 258 StructReturn, 259 260 /// The link register. 261 /// 262 /// Most RISC architectures implement calls by saving the return address in a designated 263 /// register rather than pushing it on the stack. This is represented with a `Link` argument. 264 /// 265 /// Similarly, some return instructions expect the return address in a register represented as 266 /// a `Link` return value. 267 Link, 268 269 /// The frame pointer. 270 /// 271 /// This indicates the frame pointer register which has a special meaning in some ABIs. 272 /// 273 /// The frame pointer appears as an argument and as a return value since it is a callee-saved 274 /// register. 275 FramePointer, 276 277 /// A callee-saved register. 278 /// 279 /// Some calling conventions have registers that must be saved by the callee. These registers 280 /// are represented as `CalleeSaved` arguments and return values. 281 CalleeSaved, 282 283 /// A VM context pointer. 284 /// 285 /// This is a pointer to a context struct containing details about the current sandbox. It is 286 /// used as a base pointer for `vmctx` global values. 287 VMContext, 288 289 /// A signature identifier. 290 /// 291 /// This is a special-purpose argument used to identify the calling convention expected by the 292 /// caller in an indirect call. The callee can verify that the expected signature ID matches. 293 SignatureId, 294 295 /// A stack limit pointer. 296 /// 297 /// This is a pointer to a stack limit. It is used to check the current stack pointer 298 /// against. Can only appear once in a signature. 299 StackLimit, 300 301 /// A callee TLS value. 302 /// 303 /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the 304 /// TLS-register values for the caller and the callee. This argument is used to provide the 305 /// value for the callee. 306 CalleeTLS, 307 308 /// A caller TLS value. 309 /// 310 /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the 311 /// TLS-register values for the caller and the callee. This argument is used to provide the 312 /// value for the caller. 313 CallerTLS, 314 } 315 316 impl fmt::Display for ArgumentPurpose { 317 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 318 f.write_str(match self { 319 Self::Normal => "normal", 320 Self::StructArgument(size) => return write!(f, "sarg({})", size), 321 Self::StructReturn => "sret", 322 Self::Link => "link", 323 Self::FramePointer => "fp", 324 Self::CalleeSaved => "csr", 325 Self::VMContext => "vmctx", 326 Self::SignatureId => "sigid", 327 Self::StackLimit => "stack_limit", 328 Self::CalleeTLS => "callee_tls", 329 Self::CallerTLS => "caller_tls", 330 }) 331 } 332 } 333 334 impl FromStr for ArgumentPurpose { 335 type Err = (); 336 fn from_str(s: &str) -> Result<Self, ()> { 337 match s { 338 "normal" => Ok(Self::Normal), 339 "sret" => Ok(Self::StructReturn), 340 "link" => Ok(Self::Link), 341 "fp" => Ok(Self::FramePointer), 342 "csr" => Ok(Self::CalleeSaved), 343 "vmctx" => Ok(Self::VMContext), 344 "sigid" => Ok(Self::SignatureId), 345 "stack_limit" => Ok(Self::StackLimit), 346 _ if s.starts_with("sarg(") => { 347 if !s.ends_with(")") { 348 return Err(()); 349 } 350 // Parse 'sarg(size)' 351 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?; 352 Ok(Self::StructArgument(size)) 353 } 354 _ => Err(()), 355 } 356 } 357 } 358 359 /// An external function. 360 /// 361 /// Information about a function that can be called directly with a direct `call` instruction. 362 #[derive(Clone, Debug)] 363 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 364 pub struct ExtFuncData { 365 /// Name of the external function. 366 pub name: ExternalName, 367 /// Call signature of function. 368 pub signature: SigRef, 369 /// Will this function be defined nearby, such that it will always be a certain distance away, 370 /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that 371 /// symbols meant to be preemptible cannot be considered colocated. 372 /// 373 /// If `true`, some backends may use relocation forms that have limited range. The exact 374 /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift 375 /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how 376 /// far away the target will be, it is best not to set the `colocated` flag; in general, this 377 /// flag is best used when the target is known to be in the same unit of code generation, such 378 /// as a Wasm module. 379 /// 380 /// See the documentation for [`RelocDistance`](crate::machinst::RelocDistance) for more details. A 381 /// `colocated` flag value of `true` implies `RelocDistance::Near`. 382 pub colocated: bool, 383 } 384 385 impl fmt::Display for ExtFuncData { 386 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 387 if self.colocated { 388 write!(f, "colocated ")?; 389 } 390 write!(f, "{} {}", self.name, self.signature) 391 } 392 } 393 394 impl ExtFuncData { 395 /// Return an estimate of the distance to the referred-to function symbol. 396 pub fn reloc_distance(&self) -> RelocDistance { 397 if self.colocated { 398 RelocDistance::Near 399 } else { 400 RelocDistance::Far 401 } 402 } 403 } 404 405 #[cfg(test)] 406 mod tests { 407 use super::*; 408 use crate::ir::types::{B8, F32, I32}; 409 use alloc::string::ToString; 410 411 #[test] 412 fn argument_type() { 413 let t = AbiParam::new(I32); 414 assert_eq!(t.to_string(), "i32"); 415 let mut t = t.uext(); 416 assert_eq!(t.to_string(), "i32 uext"); 417 assert_eq!(t.sext().to_string(), "i32 sext"); 418 t.purpose = ArgumentPurpose::StructReturn; 419 assert_eq!(t.to_string(), "i32 uext sret"); 420 t.legalized_to_pointer = true; 421 assert_eq!(t.to_string(), "i32 ptr uext sret"); 422 } 423 424 #[test] 425 fn argument_purpose() { 426 let all_purpose = [ 427 (ArgumentPurpose::Normal, "normal"), 428 (ArgumentPurpose::StructReturn, "sret"), 429 (ArgumentPurpose::Link, "link"), 430 (ArgumentPurpose::FramePointer, "fp"), 431 (ArgumentPurpose::CalleeSaved, "csr"), 432 (ArgumentPurpose::VMContext, "vmctx"), 433 (ArgumentPurpose::SignatureId, "sigid"), 434 (ArgumentPurpose::StackLimit, "stack_limit"), 435 (ArgumentPurpose::StructArgument(42), "sarg(42)"), 436 ]; 437 for &(e, n) in &all_purpose { 438 assert_eq!(e.to_string(), n); 439 assert_eq!(Ok(e), n.parse()); 440 } 441 } 442 443 #[test] 444 fn call_conv() { 445 for &cc in &[ 446 CallConv::Fast, 447 CallConv::Cold, 448 CallConv::SystemV, 449 CallConv::WindowsFastcall, 450 CallConv::BaldrdashSystemV, 451 CallConv::BaldrdashWindows, 452 CallConv::Baldrdash2020, 453 ] { 454 assert_eq!(Ok(cc), cc.to_string().parse()) 455 } 456 } 457 458 #[test] 459 fn signatures() { 460 let mut sig = Signature::new(CallConv::BaldrdashSystemV); 461 assert_eq!(sig.to_string(), "() baldrdash_system_v"); 462 sig.params.push(AbiParam::new(I32)); 463 assert_eq!(sig.to_string(), "(i32) baldrdash_system_v"); 464 sig.returns.push(AbiParam::new(F32)); 465 assert_eq!(sig.to_string(), "(i32) -> f32 baldrdash_system_v"); 466 sig.params.push(AbiParam::new(I32.by(4).unwrap())); 467 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 baldrdash_system_v"); 468 sig.returns.push(AbiParam::new(B8)); 469 assert_eq!( 470 sig.to_string(), 471 "(i32, i32x4) -> f32, b8 baldrdash_system_v" 472 ); 473 } 474 } 475