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