• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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