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