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
;
30 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
32 /// Ignore the argument.
34 /// The argument is either uninhabited or a ZST.
36 /// Pass the argument directly.
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.
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.
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 }
,
56 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
58 pub use attr_impl
::ArgAttribute
;
60 #[allow(non_upper_case_globals)]
63 // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
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;
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;
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
{
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
>,
105 pub fn new() -> Self {
107 regular
: ArgAttribute
::default(),
108 arg_ext
: ArgExtension
::None
,
109 pointee_size
: Size
::ZERO
,
114 pub fn ext(&mut self, ext
: ArgExtension
) -> &mut Self {
116 self.arg_ext
== ArgExtension
::None
|| self.arg_ext
== ext
,
117 "cannot set {:?} when {:?} is already set",
125 pub fn set(&mut self, attr
: ArgAttribute
) -> &mut Self {
126 self.regular
|= attr
;
130 pub fn contains(&self, attr
: ArgAttribute
) -> bool
{
131 self.regular
.contains(attr
)
135 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
142 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
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) }
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);
163 reg_ctor
!(f32, Float
, 32);
164 reg_ctor
!(f64, Float
, 64);
168 pub fn align
<C
: HasDataLayout
>(&self, cx
: &C
) -> Align
{
169 let dl
= cx
.data_layout();
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),
180 RegKind
::Float
=> match self.size
.bits() {
181 32 => dl
.f32_align
.abi
,
182 64 => dl
.f64_align
.abi
,
183 _
=> panic
!("unsupported float: {:?}", self),
185 RegKind
::Vector
=> dl
.vector_align(self.size
).abi
,
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)]
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.
205 impl From
<Reg
> for Uniform
{
206 fn from(unit
: Reg
) -> Uniform
{
207 Uniform { unit, total: unit.size }
212 pub fn align
<C
: HasDataLayout
>(&self, cx
: &C
) -> Align
{
217 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
218 pub struct CastTarget
{
219 pub prefix
: [Option
<Reg
>; 8],
221 pub attrs
: ArgAttributes
,
224 impl From
<Reg
> for CastTarget
{
225 fn from(unit
: Reg
) -> CastTarget
{
226 CastTarget
::from(Uniform
::from(unit
))
230 impl From
<Uniform
> for CastTarget
{
231 fn from(uniform
: Uniform
) -> CastTarget
{
235 attrs
: ArgAttributes
{
236 regular
: ArgAttribute
::default(),
237 arg_ext
: ArgExtension
::None
,
238 pointee_size
: Size
::ZERO
,
246 pub fn pair(a
: Reg
, b
: Reg
) -> 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
,
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() }
,
270 pub fn align
<C
: HasDataLayout
>(&self, cx
: &C
) -> Align
{
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
| {
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).
287 /// There are no leaf fields at all.
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
;
297 impl HomogeneousAggregate
{
298 /// If this is a homogeneous aggregate, returns the homogeneous
299 /// unit, else `None`.
300 pub fn unit(self) -> Option
<Reg
> {
302 HomogeneousAggregate
::Homogeneous(reg
) => Some(reg
),
303 HomogeneousAggregate
::NoData
=> None
,
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
),
314 (HomogeneousAggregate
::Homogeneous(a
), HomogeneousAggregate
::Homogeneous(b
)) => {
316 return Err(Heterogeneous
);
324 impl<'a
, Ty
> TyAndLayout
<'a
, Ty
> {
325 fn is_aggregate(&self) -> bool
{
327 Abi
::Uninhabited
| Abi
::Scalar(_
) | Abi
::Vector { .. }
=> false,
328 Abi
::ScalarPair(..) | Abi
::Aggregate { .. }
=> true,
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.
336 /// Note: We generally ignore fields of zero-sized type when computing
337 /// this value (see #56877).
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
>
344 Ty
: TyAbiInterface
<'a
, C
> + Copy
,
347 Abi
::Uninhabited
=> Err(Heterogeneous
),
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
,
355 Ok(HomogeneousAggregate
::Homogeneous(Reg { kind, size: self.size }
))
358 Abi
::Vector { .. }
=> {
359 assert
!(!self.is_zst());
360 Ok(HomogeneousAggregate
::Homogeneous(Reg
{
361 kind
: RegKind
::Vector
,
366 Abi
::ScalarPair(..) | Abi
::Aggregate { .. }
=> {
367 // Helper for computing `homogeneous_aggregate`, allowing a custom
368 // starting offset (used below for handling variants).
372 -> Result
<(HomogeneousAggregate
, Size
), Heterogeneous
> {
373 let is_union
= match layout
.fields
{
374 FieldsShape
::Primitive
=> {
375 unreachable
!("aggregates can't have `FieldsShape::Primitive`")
377 FieldsShape
::Array { count, .. }
=> {
378 assert_eq
!(start
, Size
::ZERO
);
380 let result
= if count
> 0 {
381 layout
.field(cx
, 0).homogeneous_aggregate(cx
)?
383 HomogeneousAggregate
::NoData
385 return Ok((result
, layout
.size
));
387 FieldsShape
::Union(_
) => true,
388 FieldsShape
::Arbitrary { .. }
=> false,
391 let mut result
= HomogeneousAggregate
::NoData
;
392 let mut total
= start
;
394 for i
in 0..layout
.fields
.count() {
395 if !is_union
&& total
!= layout
.fields
.offset(i
) {
396 return Err(Heterogeneous
);
399 let field
= layout
.field(cx
, i
);
401 result
= result
.merge(field
.homogeneous_aggregate(cx
)?
)?
;
403 // Keep track of the offset (without padding).
404 let size
= field
.size
;
406 total
= total
.max(size
);
415 let (mut result
, mut total
) = from_fields_at(*self, Size
::ZERO
)?
;
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).
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
)?
;
437 result
= result
.merge(variant_result
)?
;
438 total
= total
.max(variant_total
);
443 // There needs to be no padding.
444 if total
!= self.size
{
448 HomogeneousAggregate
::Homogeneous(_
) => {
449 assert_ne
!(total
, Size
::ZERO
);
451 HomogeneousAggregate
::NoData
=> {
452 assert_eq
!(total
, Size
::ZERO
);
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
>,
468 /// Dummy argument, which is emitted before the real argument.
469 pub pad
: Option
<Reg
>,
474 impl<'a
, Ty
> ArgAbi
<'a
, Ty
> {
476 cx
: &impl HasDataLayout
,
477 layout
: TyAndLayout
<'a
, Ty
>,
478 scalar_attrs
: impl Fn(&TyAndLayout
<'a
, Ty
>, abi
::Scalar
, Size
) -> ArgAttributes
,
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
)),
487 Abi
::Vector { .. }
=> PassMode
::Direct(ArgAttributes
::new()),
488 Abi
::Aggregate { .. }
=> PassMode
::Direct(ArgAttributes
::new()),
490 ArgAbi { layout, pad: None, mode }
493 fn indirect_pass_mode(layout
: &TyAndLayout
<'a
, Ty
>) -> PassMode
{
494 let mut attrs
= ArgAttributes
::new();
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
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);
509 let extra_attrs
= layout
.is_unsized().then_some(ArgAttributes
::new());
511 PassMode
::Indirect { attrs, extra_attrs, on_stack: false }
514 pub fn make_indirect(&mut self) {
516 PassMode
::Direct(_
) | PassMode
::Pair(_
, _
) => {}
517 PassMode
::Indirect { attrs: _, extra_attrs: None, on_stack: false }
=> return,
518 _
=> panic
!("Tried to make {:?} indirect", self.mode
),
521 self.mode
= Self::indirect_pass_mode(&self.layout
);
524 pub fn make_indirect_byval(&mut self) {
525 self.make_indirect();
527 PassMode
::Indirect { attrs: _, extra_attrs: _, ref mut on_stack }
=> {
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
{
541 attrs
.ext(ArgExtension
::Sext
)
543 attrs
.ext(ArgExtension
::Zext
)
551 pub fn cast_to
<T
: Into
<CastTarget
>>(&mut self, target
: T
) {
552 self.mode
= PassMode
::Cast(target
.into());
555 pub fn pad_with(&mut self, reg
: Reg
) {
556 self.pad
= Some(reg
);
559 pub fn is_indirect(&self) -> bool
{
560 matches
!(self.mode
, PassMode
::Indirect { .. }
)
563 pub fn is_sized_indirect(&self) -> bool
{
564 matches
!(self.mode
, PassMode
::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
)
567 pub fn is_unsized_indirect(&self) -> bool
{
568 matches
!(self.mode
, PassMode
::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
)
571 pub fn is_ignore(&self) -> bool
{
572 matches
!(self.mode
, PassMode
::Ignore
)
576 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
578 // General language calling conventions, for which every target
579 // should have its own backend (e.g. LLVM) support.
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.
588 // Target-specific calling conventions.
607 AvrNonBlockingInterrupt
,
610 /// Metadata describing how the arguments to a native function
611 /// should be passed in order to respect the native ABI.
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
>>,
620 /// LLVM return type.
621 pub ret
: ArgAbi
<'a
, Ty
>,
623 pub c_variadic
: bool
,
625 /// The count of non-variadic arguments.
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,
633 pub can_unwind
: bool
,
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 }
,
643 impl fmt
::Display
for AdjustForForeignAbiError
{
644 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
646 Self::Unsupported { arch, abi }
=> {
647 write
!(f
, "target architecture {:?} does not support `extern {}` ABI", arch
, abi
)
653 impl<'a
, Ty
> FnAbi
<'a
, Ty
> {
654 pub fn adjust_for_foreign_abi
<C
>(
658 ) -> Result
<(), AdjustForForeignAbiError
>
660 Ty
: TyAbiInterface
<'a
, C
> + Copy
,
661 C
: HasDataLayout
+ HasTargetSpec
,
663 if abi
== spec
::abi
::Abi
::X86Interrupt
{
664 if let Some(arg
) = self.args
.first_mut() {
665 arg
.make_indirect_byval();
670 match &cx
.target_spec().arch
[..] {
672 let flavor
= if let spec
::abi
::Abi
::Fastcall { .. }
= abi
{
673 x86
::Flavor
::Fastcall
677 x86
::compute_abi_info(cx
, self, flavor
);
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),
683 if cx
.target_spec().is_like_windows
{
684 x86_win64
::compute_abi_info(self)
686 x86_64
::compute_abi_info(cx
, self)
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),
705 if cx
.target_spec().adjust_abi(abi
) == spec
::abi
::Abi
::PtxKernel
{
706 nvptx64
::compute_ptx_kernel_abi_info(cx
, self)
708 nvptx64
::compute_abi_info(self)
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)
717 wasm
::compute_c_abi_info(cx
, self)
720 "asmjs" => wasm
::compute_c_abi_info(cx
, self),
721 "bpf" => bpf
::compute_abi_info(self),
723 return Err(AdjustForForeignAbiError
::Unsupported
{
724 arch
: Symbol
::intern(arch
),