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