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