1 use crate::abi::{self, Abi, Align, FieldsShape, Size}; 2 use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; 3 use crate::spec::{self, HasTargetSpec}; 4 use rustc_span::Symbol; 5 use std::str::FromStr; 6 7 mod aarch64; 8 mod amdgpu; 9 mod arm; 10 mod avr; 11 mod bpf; 12 mod hexagon; 13 mod loongarch; 14 mod m68k; 15 mod mips; 16 mod mips64; 17 mod msp430; 18 mod nvptx64; 19 mod powerpc; 20 mod powerpc64; 21 mod riscv; 22 mod s390x; 23 mod sparc; 24 mod sparc64; 25 mod wasm; 26 mod x86; 27 mod x86_64; 28 mod x86_win64; 29 30 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 31 pub enum PassMode { 32 /// Ignore the argument. 33 /// 34 /// The argument is either uninhabited or a ZST. 35 Ignore, 36 /// Pass the argument directly. 37 /// 38 /// The argument has a layout abi of `Scalar`, `Vector` or in rare cases `Aggregate`. 39 Direct(ArgAttributes), 40 /// Pass a pair's elements directly in two arguments. 41 /// 42 /// The argument has a layout abi of `ScalarPair`. 43 Pair(ArgAttributes, ArgAttributes), 44 /// Pass the argument after casting it, to either a single uniform or a 45 /// pair of registers. The bool indicates if a `Reg::i32()` dummy argument 46 /// is emitted before the real argument. 47 Cast(Box<CastTarget>, bool), 48 /// Pass the argument indirectly via a hidden pointer. 49 /// The `extra_attrs` value, if any, is for the extra data (vtable or length) 50 /// which indicates that it refers to an unsized rvalue. 51 /// `on_stack` defines that the value should be passed at a fixed 52 /// stack offset in accordance to the ABI rather than passed using a 53 /// pointer. This corresponds to the `byval` LLVM argument attribute. 54 Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool }, 55 } 56 57 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest 58 // of this module 59 pub use attr_impl::ArgAttribute; 60 61 #[allow(non_upper_case_globals)] 62 #[allow(unused)] 63 mod attr_impl { 64 // The subset of llvm::Attribute needed for arguments, packed into a bitfield. 65 bitflags::bitflags! { 66 #[derive(Default, HashStable_Generic)] 67 pub struct ArgAttribute: u8 { 68 const NoAlias = 1 << 1; 69 const NoCapture = 1 << 2; 70 const NonNull = 1 << 3; 71 const ReadOnly = 1 << 4; 72 const InReg = 1 << 5; 73 const NoUndef = 1 << 6; 74 } 75 } 76 } 77 78 /// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum 79 /// defines if this extension should be zero-extension or sign-extension when necessary. When it is 80 /// not necessary to extend the argument, this enum is ignored. 81 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 82 pub enum ArgExtension { 83 None, 84 Zext, 85 Sext, 86 } 87 88 /// A compact representation of LLVM attributes (at least those relevant for this module) 89 /// that can be manipulated without interacting with LLVM's Attribute machinery. 90 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 91 pub struct ArgAttributes { 92 pub regular: ArgAttribute, 93 pub arg_ext: ArgExtension, 94 /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call 95 /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes). 96 pub pointee_size: Size, 97 pub pointee_align: Option<Align>, 98 } 99 100 impl ArgAttributes { new() -> Self101 pub fn new() -> Self { 102 ArgAttributes { 103 regular: ArgAttribute::default(), 104 arg_ext: ArgExtension::None, 105 pointee_size: Size::ZERO, 106 pointee_align: None, 107 } 108 } 109 ext(&mut self, ext: ArgExtension) -> &mut Self110 pub fn ext(&mut self, ext: ArgExtension) -> &mut Self { 111 assert!( 112 self.arg_ext == ArgExtension::None || self.arg_ext == ext, 113 "cannot set {:?} when {:?} is already set", 114 ext, 115 self.arg_ext 116 ); 117 self.arg_ext = ext; 118 self 119 } 120 set(&mut self, attr: ArgAttribute) -> &mut Self121 pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { 122 self.regular |= attr; 123 self 124 } 125 contains(&self, attr: ArgAttribute) -> bool126 pub fn contains(&self, attr: ArgAttribute) -> bool { 127 self.regular.contains(attr) 128 } 129 } 130 131 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 132 pub enum RegKind { 133 Integer, 134 Float, 135 Vector, 136 } 137 138 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 139 pub struct Reg { 140 pub kind: RegKind, 141 pub size: Size, 142 } 143 144 macro_rules! reg_ctor { 145 ($name:ident, $kind:ident, $bits:expr) => { 146 pub fn $name() -> Reg { 147 Reg { kind: RegKind::$kind, size: Size::from_bits($bits) } 148 } 149 }; 150 } 151 152 impl Reg { 153 reg_ctor!(i8, Integer, 8); 154 reg_ctor!(i16, Integer, 16); 155 reg_ctor!(i32, Integer, 32); 156 reg_ctor!(i64, Integer, 64); 157 reg_ctor!(i128, Integer, 128); 158 159 reg_ctor!(f32, Float, 32); 160 reg_ctor!(f64, Float, 64); 161 } 162 163 impl Reg { align<C: HasDataLayout>(&self, cx: &C) -> Align164 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { 165 let dl = cx.data_layout(); 166 match self.kind { 167 RegKind::Integer => match self.size.bits() { 168 1 => dl.i1_align.abi, 169 2..=8 => dl.i8_align.abi, 170 9..=16 => dl.i16_align.abi, 171 17..=32 => dl.i32_align.abi, 172 33..=64 => dl.i64_align.abi, 173 65..=128 => dl.i128_align.abi, 174 _ => panic!("unsupported integer: {self:?}"), 175 }, 176 RegKind::Float => match self.size.bits() { 177 32 => dl.f32_align.abi, 178 64 => dl.f64_align.abi, 179 _ => panic!("unsupported float: {self:?}"), 180 }, 181 RegKind::Vector => dl.vector_align(self.size).abi, 182 } 183 } 184 } 185 186 /// An argument passed entirely registers with the 187 /// same kind (e.g., HFA / HVA on PPC64 and AArch64). 188 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 189 pub struct Uniform { 190 pub unit: Reg, 191 192 /// The total size of the argument, which can be: 193 /// * equal to `unit.size` (one scalar/vector), 194 /// * a multiple of `unit.size` (an array of scalar/vectors), 195 /// * if `unit.kind` is `Integer`, the last element 196 /// can be shorter, i.e., `{ i64, i64, i32 }` for 197 /// 64-bit integers with a total size of 20 bytes. 198 pub total: Size, 199 } 200 201 impl From<Reg> for Uniform { from(unit: Reg) -> Uniform202 fn from(unit: Reg) -> Uniform { 203 Uniform { unit, total: unit.size } 204 } 205 } 206 207 impl Uniform { align<C: HasDataLayout>(&self, cx: &C) -> Align208 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { 209 self.unit.align(cx) 210 } 211 } 212 213 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 214 pub struct CastTarget { 215 pub prefix: [Option<Reg>; 8], 216 pub rest: Uniform, 217 pub attrs: ArgAttributes, 218 } 219 220 impl From<Reg> for CastTarget { from(unit: Reg) -> CastTarget221 fn from(unit: Reg) -> CastTarget { 222 CastTarget::from(Uniform::from(unit)) 223 } 224 } 225 226 impl From<Uniform> for CastTarget { from(uniform: Uniform) -> CastTarget227 fn from(uniform: Uniform) -> CastTarget { 228 CastTarget { 229 prefix: [None; 8], 230 rest: uniform, 231 attrs: ArgAttributes { 232 regular: ArgAttribute::default(), 233 arg_ext: ArgExtension::None, 234 pointee_size: Size::ZERO, 235 pointee_align: None, 236 }, 237 } 238 } 239 } 240 241 impl CastTarget { pair(a: Reg, b: Reg) -> CastTarget242 pub fn pair(a: Reg, b: Reg) -> CastTarget { 243 CastTarget { 244 prefix: [Some(a), None, None, None, None, None, None, None], 245 rest: Uniform::from(b), 246 attrs: ArgAttributes { 247 regular: ArgAttribute::default(), 248 arg_ext: ArgExtension::None, 249 pointee_size: Size::ZERO, 250 pointee_align: None, 251 }, 252 } 253 } 254 size<C: HasDataLayout>(&self, _cx: &C) -> Size255 pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size { 256 let mut size = self.rest.total; 257 for i in 0..self.prefix.iter().count() { 258 match self.prefix[i] { 259 Some(v) => size += v.size, 260 None => {} 261 } 262 } 263 return size; 264 } 265 align<C: HasDataLayout>(&self, cx: &C) -> Align266 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { 267 self.prefix 268 .iter() 269 .filter_map(|x| x.map(|reg| reg.align(cx))) 270 .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| { 271 acc.max(align) 272 }) 273 } 274 } 275 276 /// Return value from the `homogeneous_aggregate` test function. 277 #[derive(Copy, Clone, Debug)] 278 pub enum HomogeneousAggregate { 279 /// Yes, all the "leaf fields" of this struct are passed in the 280 /// same way (specified in the `Reg` value). 281 Homogeneous(Reg), 282 283 /// There are no leaf fields at all. 284 NoData, 285 } 286 287 /// Error from the `homogeneous_aggregate` test function, indicating 288 /// there are distinct leaf fields passed in different ways, 289 /// or this is uninhabited. 290 #[derive(Copy, Clone, Debug)] 291 pub struct Heterogeneous; 292 293 impl HomogeneousAggregate { 294 /// If this is a homogeneous aggregate, returns the homogeneous 295 /// unit, else `None`. unit(self) -> Option<Reg>296 pub fn unit(self) -> Option<Reg> { 297 match self { 298 HomogeneousAggregate::Homogeneous(reg) => Some(reg), 299 HomogeneousAggregate::NoData => None, 300 } 301 } 302 303 /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in 304 /// the same `struct`. Only succeeds if only one of them has any data, 305 /// or both units are identical. merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous>306 fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> { 307 match (self, other) { 308 (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x), 309 310 (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => { 311 if a != b { 312 return Err(Heterogeneous); 313 } 314 Ok(self) 315 } 316 } 317 } 318 } 319 320 impl<'a, Ty> TyAndLayout<'a, Ty> { is_aggregate(&self) -> bool321 fn is_aggregate(&self) -> bool { 322 match self.abi { 323 Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, 324 Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, 325 } 326 } 327 328 /// Returns `Homogeneous` if this layout is an aggregate containing fields of 329 /// only a single type (e.g., `(u32, u32)`). Such aggregates are often 330 /// special-cased in ABIs. 331 /// 332 /// Note: We generally ignore fields of zero-sized type when computing 333 /// this value (see #56877). 334 /// 335 /// This is public so that it can be used in unit tests, but 336 /// should generally only be relevant to the ABI details of 337 /// specific targets. homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous> where Ty: TyAbiInterface<'a, C> + Copy,338 pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous> 339 where 340 Ty: TyAbiInterface<'a, C> + Copy, 341 { 342 match self.abi { 343 Abi::Uninhabited => Err(Heterogeneous), 344 345 // The primitive for this algorithm. 346 Abi::Scalar(scalar) => { 347 let kind = match scalar.primitive() { 348 abi::Int(..) | abi::Pointer(_) => RegKind::Integer, 349 abi::F32 | abi::F64 => RegKind::Float, 350 }; 351 Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) 352 } 353 354 Abi::Vector { .. } => { 355 assert!(!self.is_zst()); 356 Ok(HomogeneousAggregate::Homogeneous(Reg { 357 kind: RegKind::Vector, 358 size: self.size, 359 })) 360 } 361 362 Abi::ScalarPair(..) | Abi::Aggregate { .. } => { 363 // Helper for computing `homogeneous_aggregate`, allowing a custom 364 // starting offset (used below for handling variants). 365 let from_fields_at = 366 |layout: Self, 367 start: Size| 368 -> Result<(HomogeneousAggregate, Size), Heterogeneous> { 369 let is_union = match layout.fields { 370 FieldsShape::Primitive => { 371 unreachable!("aggregates can't have `FieldsShape::Primitive`") 372 } 373 FieldsShape::Array { count, .. } => { 374 assert_eq!(start, Size::ZERO); 375 376 let result = if count > 0 { 377 layout.field(cx, 0).homogeneous_aggregate(cx)? 378 } else { 379 HomogeneousAggregate::NoData 380 }; 381 return Ok((result, layout.size)); 382 } 383 FieldsShape::Union(_) => true, 384 FieldsShape::Arbitrary { .. } => false, 385 }; 386 387 let mut result = HomogeneousAggregate::NoData; 388 let mut total = start; 389 390 for i in 0..layout.fields.count() { 391 if !is_union && total != layout.fields.offset(i) { 392 return Err(Heterogeneous); 393 } 394 395 let field = layout.field(cx, i); 396 397 result = result.merge(field.homogeneous_aggregate(cx)?)?; 398 399 // Keep track of the offset (without padding). 400 let size = field.size; 401 if is_union { 402 total = total.max(size); 403 } else { 404 total += size; 405 } 406 } 407 408 Ok((result, total)) 409 }; 410 411 let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; 412 413 match &self.variants { 414 abi::Variants::Single { .. } => {} 415 abi::Variants::Multiple { variants, .. } => { 416 // Treat enum variants like union members. 417 // HACK(eddyb) pretend the `enum` field (discriminant) 418 // is at the start of every variant (otherwise the gap 419 // at the start of all variants would disqualify them). 420 // 421 // NB: for all tagged `enum`s (which include all non-C-like 422 // `enum`s with defined FFI representation), this will 423 // match the homogeneous computation on the equivalent 424 // `struct { tag; union { variant1; ... } }` and/or 425 // `union { struct { tag; variant1; } ... }` 426 // (the offsets of variant fields should be identical 427 // between the two for either to be a homogeneous aggregate). 428 let variant_start = total; 429 for variant_idx in variants.indices() { 430 let (variant_result, variant_total) = 431 from_fields_at(self.for_variant(cx, variant_idx), variant_start)?; 432 433 result = result.merge(variant_result)?; 434 total = total.max(variant_total); 435 } 436 } 437 } 438 439 // There needs to be no padding. 440 if total != self.size { 441 Err(Heterogeneous) 442 } else { 443 match result { 444 HomogeneousAggregate::Homogeneous(_) => { 445 assert_ne!(total, Size::ZERO); 446 } 447 HomogeneousAggregate::NoData => { 448 assert_eq!(total, Size::ZERO); 449 } 450 } 451 Ok(result) 452 } 453 } 454 } 455 } 456 } 457 458 /// Information about how to pass an argument to, 459 /// or return a value from, a function, under some ABI. 460 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 461 pub struct ArgAbi<'a, Ty> { 462 pub layout: TyAndLayout<'a, Ty>, 463 pub mode: PassMode, 464 } 465 466 impl<'a, Ty> ArgAbi<'a, Ty> { new( cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes, ) -> Self467 pub fn new( 468 cx: &impl HasDataLayout, 469 layout: TyAndLayout<'a, Ty>, 470 scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes, 471 ) -> Self { 472 let mode = match layout.abi { 473 Abi::Uninhabited => PassMode::Ignore, 474 Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)), 475 Abi::ScalarPair(a, b) => PassMode::Pair( 476 scalar_attrs(&layout, a, Size::ZERO), 477 scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), 478 ), 479 Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), 480 Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()), 481 }; 482 ArgAbi { layout, mode } 483 } 484 indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode485 fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode { 486 let mut attrs = ArgAttributes::new(); 487 488 // For non-immediate arguments the callee gets its own copy of 489 // the value on the stack, so there are no aliases. It's also 490 // program-invisible so can't possibly capture 491 attrs 492 .set(ArgAttribute::NoAlias) 493 .set(ArgAttribute::NoCapture) 494 .set(ArgAttribute::NonNull) 495 .set(ArgAttribute::NoUndef); 496 attrs.pointee_size = layout.size; 497 // FIXME(eddyb) We should be doing this, but at least on 498 // i686-pc-windows-msvc, it results in wrong stack offsets. 499 // attrs.pointee_align = Some(layout.align.abi); 500 501 let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new()); 502 503 PassMode::Indirect { attrs, extra_attrs, on_stack: false } 504 } 505 make_indirect(&mut self)506 pub fn make_indirect(&mut self) { 507 match self.mode { 508 PassMode::Direct(_) | PassMode::Pair(_, _) => {} 509 PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return, 510 _ => panic!("Tried to make {:?} indirect", self.mode), 511 } 512 513 self.mode = Self::indirect_pass_mode(&self.layout); 514 } 515 make_indirect_byval(&mut self)516 pub fn make_indirect_byval(&mut self) { 517 self.make_indirect(); 518 match self.mode { 519 PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => { 520 *on_stack = true; 521 } 522 _ => unreachable!(), 523 } 524 } 525 extend_integer_width_to(&mut self, bits: u64)526 pub fn extend_integer_width_to(&mut self, bits: u64) { 527 // Only integers have signedness 528 if let Abi::Scalar(scalar) = self.layout.abi { 529 if let abi::Int(i, signed) = scalar.primitive() { 530 if i.size().bits() < bits { 531 if let PassMode::Direct(ref mut attrs) = self.mode { 532 if signed { 533 attrs.ext(ArgExtension::Sext) 534 } else { 535 attrs.ext(ArgExtension::Zext) 536 }; 537 } 538 } 539 } 540 } 541 } 542 cast_to<T: Into<CastTarget>>(&mut self, target: T)543 pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { 544 self.mode = PassMode::Cast(Box::new(target.into()), false); 545 } 546 cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool)547 pub fn cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool) { 548 self.mode = PassMode::Cast(Box::new(target.into()), pad_i32); 549 } 550 is_indirect(&self) -> bool551 pub fn is_indirect(&self) -> bool { 552 matches!(self.mode, PassMode::Indirect { .. }) 553 } 554 is_sized_indirect(&self) -> bool555 pub fn is_sized_indirect(&self) -> bool { 556 matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }) 557 } 558 is_unsized_indirect(&self) -> bool559 pub fn is_unsized_indirect(&self) -> bool { 560 matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }) 561 } 562 is_ignore(&self) -> bool563 pub fn is_ignore(&self) -> bool { 564 matches!(self.mode, PassMode::Ignore) 565 } 566 } 567 568 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 569 pub enum Conv { 570 // General language calling conventions, for which every target 571 // should have its own backend (e.g. LLVM) support. 572 C, 573 Rust, 574 575 /// For things unlikely to be called, where smaller caller codegen is 576 /// preferred over raw speed. 577 /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. 578 RustCold, 579 580 // Target-specific calling conventions. 581 ArmAapcs, 582 CCmseNonSecureCall, 583 584 Msp430Intr, 585 586 PtxKernel, 587 588 X86Fastcall, 589 X86Intr, 590 X86Stdcall, 591 X86ThisCall, 592 X86VectorCall, 593 594 X86_64SysV, 595 X86_64Win64, 596 597 AmdGpuKernel, 598 AvrInterrupt, 599 AvrNonBlockingInterrupt, 600 } 601 602 /// Metadata describing how the arguments to a native function 603 /// should be passed in order to respect the native ABI. 604 /// 605 /// I will do my best to describe this structure, but these 606 /// comments are reverse-engineered and may be inaccurate. -NDM 607 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] 608 pub struct FnAbi<'a, Ty> { 609 /// The LLVM types of each argument. 610 pub args: Box<[ArgAbi<'a, Ty>]>, 611 612 /// LLVM return type. 613 pub ret: ArgAbi<'a, Ty>, 614 615 pub c_variadic: bool, 616 617 /// The count of non-variadic arguments. 618 /// 619 /// Should only be different from args.len() when c_variadic is true. 620 /// This can be used to know whether an argument is variadic or not. 621 pub fixed_count: u32, 622 623 pub conv: Conv, 624 625 pub can_unwind: bool, 626 } 627 628 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. 629 #[derive(Copy, Clone, Debug, HashStable_Generic)] 630 pub enum AdjustForForeignAbiError { 631 /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs. 632 Unsupported { arch: Symbol, abi: spec::abi::Abi }, 633 } 634 635 impl<'a, Ty> FnAbi<'a, Ty> { adjust_for_foreign_abi<C>( &mut self, cx: &C, abi: spec::abi::Abi, ) -> Result<(), AdjustForForeignAbiError> where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec,636 pub fn adjust_for_foreign_abi<C>( 637 &mut self, 638 cx: &C, 639 abi: spec::abi::Abi, 640 ) -> Result<(), AdjustForForeignAbiError> 641 where 642 Ty: TyAbiInterface<'a, C> + Copy, 643 C: HasDataLayout + HasTargetSpec, 644 { 645 if abi == spec::abi::Abi::X86Interrupt { 646 if let Some(arg) = self.args.first_mut() { 647 arg.make_indirect_byval(); 648 } 649 return Ok(()); 650 } 651 652 match &cx.target_spec().arch[..] { 653 "x86" => { 654 let flavor = if let spec::abi::Abi::Fastcall { .. } 655 | spec::abi::Abi::Vectorcall { .. } = abi 656 { 657 x86::Flavor::FastcallOrVectorcall 658 } else { 659 x86::Flavor::General 660 }; 661 x86::compute_abi_info(cx, self, flavor); 662 } 663 "x86_64" => match abi { 664 spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), 665 spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self), 666 _ => { 667 if cx.target_spec().is_like_windows { 668 x86_win64::compute_abi_info(self) 669 } else { 670 x86_64::compute_abi_info(cx, self) 671 } 672 } 673 }, 674 "aarch64" => { 675 let param_policy = if cx.target_spec().is_like_osx { 676 aarch64::ParamExtension::ExtendTo32Bits 677 } else { 678 aarch64::ParamExtension::NoExtension 679 }; 680 aarch64::compute_abi_info(cx, self, param_policy) 681 } 682 "amdgpu" => amdgpu::compute_abi_info(cx, self), 683 "arm" => arm::compute_abi_info(cx, self), 684 "avr" => avr::compute_abi_info(self), 685 "loongarch64" => loongarch::compute_abi_info(cx, self), 686 "m68k" => m68k::compute_abi_info(self), 687 "mips" => mips::compute_abi_info(cx, self), 688 "mips64" => mips64::compute_abi_info(cx, self), 689 "powerpc" => powerpc::compute_abi_info(self), 690 "powerpc64" => powerpc64::compute_abi_info(cx, self), 691 "s390x" => s390x::compute_abi_info(cx, self), 692 "msp430" => msp430::compute_abi_info(self), 693 "sparc" => sparc::compute_abi_info(cx, self), 694 "sparc64" => sparc64::compute_abi_info(cx, self), 695 "nvptx64" => { 696 if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel { 697 nvptx64::compute_ptx_kernel_abi_info(cx, self) 698 } else { 699 nvptx64::compute_abi_info(self) 700 } 701 } 702 "hexagon" => hexagon::compute_abi_info(self), 703 "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), 704 "wasm32" | "wasm64" => { 705 if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::Wasm { 706 wasm::compute_wasm_abi_info(self) 707 } else { 708 wasm::compute_c_abi_info(cx, self) 709 } 710 } 711 "asmjs" => wasm::compute_c_abi_info(cx, self), 712 "bpf" => bpf::compute_abi_info(self), 713 arch => { 714 return Err(AdjustForForeignAbiError::Unsupported { 715 arch: Symbol::intern(arch), 716 abi, 717 }); 718 } 719 } 720 721 Ok(()) 722 } 723 } 724 725 impl FromStr for Conv { 726 type Err = String; 727 from_str(s: &str) -> Result<Self, Self::Err>728 fn from_str(s: &str) -> Result<Self, Self::Err> { 729 match s { 730 "C" => Ok(Conv::C), 731 "Rust" => Ok(Conv::Rust), 732 "RustCold" => Ok(Conv::Rust), 733 "ArmAapcs" => Ok(Conv::ArmAapcs), 734 "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), 735 "Msp430Intr" => Ok(Conv::Msp430Intr), 736 "PtxKernel" => Ok(Conv::PtxKernel), 737 "X86Fastcall" => Ok(Conv::X86Fastcall), 738 "X86Intr" => Ok(Conv::X86Intr), 739 "X86Stdcall" => Ok(Conv::X86Stdcall), 740 "X86ThisCall" => Ok(Conv::X86ThisCall), 741 "X86VectorCall" => Ok(Conv::X86VectorCall), 742 "X86_64SysV" => Ok(Conv::X86_64SysV), 743 "X86_64Win64" => Ok(Conv::X86_64Win64), 744 "AmdGpuKernel" => Ok(Conv::AmdGpuKernel), 745 "AvrInterrupt" => Ok(Conv::AvrInterrupt), 746 "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt), 747 _ => Err(format!("'{s}' is not a valid value for entry function call convention.")), 748 } 749 } 750 } 751 752 // Some types are used a lot. Make sure they don't unintentionally get bigger. 753 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] 754 mod size_asserts { 755 use super::*; 756 use rustc_data_structures::static_assert_size; 757 // tidy-alphabetical-start 758 static_assert_size!(ArgAbi<'_, usize>, 56); 759 static_assert_size!(FnAbi<'_, usize>, 80); 760 // tidy-alphabetical-end 761 } 762