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