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(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 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 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 },
57 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
59 pub use attr_impl::ArgAttribute;
61 #[allow(non_upper_case_globals)]
64 // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
66 #[derive(Default, HashStable_Generic)]
67 pub struct ArgAttribute: u16 {
68 const NoAlias = 1 << 1;
69 const NoCapture = 1 << 2;
70 const NonNull = 1 << 3;
71 const ReadOnly = 1 << 4;
73 // Due to past miscompiles in LLVM, we use a separate attribute for
74 // &mut arguments, so that the codegen backend can decide whether
75 // or not to actually emit the attribute. It can also be controlled
76 // with the `-Zmutable-noalias` debugging option.
77 const NoAliasMutRef = 1 << 6;
78 const NoUndef = 1 << 7;
83 /// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
84 /// defines if this extension should be zero-extension or sign-extension when necessary. When it is
85 /// not necessary to extend the argument, this enum is ignored.
86 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
87 pub enum ArgExtension {
93 /// A compact representation of LLVM attributes (at least those relevant for this module)
94 /// that can be manipulated without interacting with LLVM's Attribute machinery.
95 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
96 pub struct ArgAttributes {
97 pub regular: ArgAttribute,
98 pub arg_ext: ArgExtension,
99 /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
100 /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
101 pub pointee_size: Size,
102 pub pointee_align: Option<Align>,
106 pub fn new() -> Self {
108 regular: ArgAttribute::default(),
109 arg_ext: ArgExtension::None,
110 pointee_size: Size::ZERO,
115 pub fn ext(&mut self, ext: ArgExtension) -> &mut Self {
117 self.arg_ext == ArgExtension::None || self.arg_ext == ext,
118 "cannot set {:?} when {:?} is already set",
126 pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
127 self.regular |= attr;
131 pub fn contains(&self, attr: ArgAttribute) -> bool {
132 self.regular.contains(attr)
136 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
143 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
149 macro_rules! reg_ctor {
150 ($name:ident, $kind:ident, $bits:expr) => {
151 pub fn $name() -> Reg {
152 Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
158 reg_ctor!(i8, Integer, 8);
159 reg_ctor!(i16, Integer, 16);
160 reg_ctor!(i32, Integer, 32);
161 reg_ctor!(i64, Integer, 64);
162 reg_ctor!(i128, Integer, 128);
164 reg_ctor!(f32, Float, 32);
165 reg_ctor!(f64, Float, 64);
169 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
170 let dl = cx.data_layout();
172 RegKind::Integer => match self.size.bits() {
173 1 => dl.i1_align.abi,
174 2..=8 => dl.i8_align.abi,
175 9..=16 => dl.i16_align.abi,
176 17..=32 => dl.i32_align.abi,
177 33..=64 => dl.i64_align.abi,
178 65..=128 => dl.i128_align.abi,
179 _ => panic!("unsupported integer: {:?}", self),
181 RegKind::Float => match self.size.bits() {
182 32 => dl.f32_align.abi,
183 64 => dl.f64_align.abi,
184 _ => panic!("unsupported float: {:?}", self),
186 RegKind::Vector => dl.vector_align(self.size).abi,
191 /// An argument passed entirely registers with the
192 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
193 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
197 /// The total size of the argument, which can be:
198 /// * equal to `unit.size` (one scalar/vector),
199 /// * a multiple of `unit.size` (an array of scalar/vectors),
200 /// * if `unit.kind` is `Integer`, the last element
201 /// can be shorter, i.e., `{ i64, i64, i32 }` for
202 /// 64-bit integers with a total size of 20 bytes.
206 impl From<Reg> for Uniform {
207 fn from(unit: Reg) -> Uniform {
208 Uniform { unit, total: unit.size }
213 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
218 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
219 pub struct CastTarget {
220 pub prefix: [Option<Reg>; 8],
222 pub attrs: ArgAttributes,
225 impl From<Reg> for CastTarget {
226 fn from(unit: Reg) -> CastTarget {
227 CastTarget::from(Uniform::from(unit))
231 impl From<Uniform> for CastTarget {
232 fn from(uniform: Uniform) -> CastTarget {
236 attrs: ArgAttributes {
237 regular: ArgAttribute::default(),
238 arg_ext: ArgExtension::None,
239 pointee_size: Size::ZERO,
247 pub fn pair(a: Reg, b: Reg) -> CastTarget {
249 prefix: [Some(a), None, None, None, None, None, None, None],
250 rest: Uniform::from(b),
251 attrs: ArgAttributes {
252 regular: ArgAttribute::default(),
253 arg_ext: ArgExtension::None,
254 pointee_size: Size::ZERO,
260 pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
261 let mut size = self.rest.total;
262 for i in 0..self.prefix.iter().count() {
263 match self.prefix[i] {
264 Some(v) => size += Size { raw: v.size.bytes() },
271 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
274 .filter_map(|x| x.map(|reg| reg.align(cx)))
275 .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
281 /// Return value from the `homogeneous_aggregate` test function.
282 #[derive(Copy, Clone, Debug)]
283 pub enum HomogeneousAggregate {
284 /// Yes, all the "leaf fields" of this struct are passed in the
285 /// same way (specified in the `Reg` value).
288 /// There are no leaf fields at all.
292 /// Error from the `homogeneous_aggregate` test function, indicating
293 /// there are distinct leaf fields passed in different ways,
294 /// or this is uninhabited.
295 #[derive(Copy, Clone, Debug)]
296 pub struct Heterogeneous;
298 impl HomogeneousAggregate {
299 /// If this is a homogeneous aggregate, returns the homogeneous
300 /// unit, else `None`.
301 pub fn unit(self) -> Option<Reg> {
303 HomogeneousAggregate::Homogeneous(reg) => Some(reg),
304 HomogeneousAggregate::NoData => None,
308 /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
309 /// the same `struct`. Only succeeds if only one of them has any data,
310 /// or both units are identical.
311 fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
312 match (self, other) {
313 (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
315 (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
317 return Err(Heterogeneous);
325 impl<'a, Ty> TyAndLayout<'a, Ty> {
326 fn is_aggregate(&self) -> bool {
328 Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
329 Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
333 /// Returns `Homogeneous` if this layout is an aggregate containing fields of
334 /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
335 /// special-cased in ABIs.
337 /// Note: We generally ignore fields of zero-sized type when computing
338 /// this value (see #56877).
340 /// This is public so that it can be used in unit tests, but
341 /// should generally only be relevant to the ABI details of
342 /// specific targets.
343 pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
345 Ty: TyAbiInterface<'a, C> + Copy,
348 Abi::Uninhabited => Err(Heterogeneous),
350 // The primitive for this algorithm.
351 Abi::Scalar(scalar) => {
352 let kind = match scalar.primitive() {
353 abi::Int(..) | abi::Pointer => RegKind::Integer,
354 abi::F32 | abi::F64 => RegKind::Float,
356 Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
359 Abi::Vector { .. } => {
360 assert!(!self.is_zst());
361 Ok(HomogeneousAggregate::Homogeneous(Reg {
362 kind: RegKind::Vector,
367 Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
368 // Helper for computing `homogeneous_aggregate`, allowing a custom
369 // starting offset (used below for handling variants).
373 -> Result<(HomogeneousAggregate, Size), Heterogeneous> {
374 let is_union = match layout.fields {
375 FieldsShape::Primitive => {
376 unreachable!("aggregates can't have `FieldsShape::Primitive`")
378 FieldsShape::Array { count, .. } => {
379 assert_eq!(start, Size::ZERO);
381 let result = if count > 0 {
382 layout.field(cx, 0).homogeneous_aggregate(cx)?
384 HomogeneousAggregate::NoData
386 return Ok((result, layout.size));
388 FieldsShape::Union(_) => true,
389 FieldsShape::Arbitrary { .. } => false,
392 let mut result = HomogeneousAggregate::NoData;
393 let mut total = start;
395 for i in 0..layout.fields.count() {
396 if !is_union && total != layout.fields.offset(i) {
397 return Err(Heterogeneous);
400 let field = layout.field(cx, i);
402 result = result.merge(field.homogeneous_aggregate(cx)?)?;
404 // Keep track of the offset (without padding).
405 let size = field.size;
407 total = total.max(size);
416 let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
418 match &self.variants {
419 abi::Variants::Single { .. } => {}
420 abi::Variants::Multiple { variants, .. } => {
421 // Treat enum variants like union members.
422 // HACK(eddyb) pretend the `enum` field (discriminant)
423 // is at the start of every variant (otherwise the gap
424 // at the start of all variants would disqualify them).
426 // NB: for all tagged `enum`s (which include all non-C-like
427 // `enum`s with defined FFI representation), this will
428 // match the homogeneous computation on the equivalent
429 // `struct { tag; union { variant1; ... } }` and/or
430 // `union { struct { tag; variant1; } ... }`
431 // (the offsets of variant fields should be identical
432 // between the two for either to be a homogeneous aggregate).
433 let variant_start = total;
434 for variant_idx in variants.indices() {
435 let (variant_result, variant_total) =
436 from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
438 result = result.merge(variant_result)?;
439 total = total.max(variant_total);
444 // There needs to be no padding.
445 if total != self.size {
449 HomogeneousAggregate::Homogeneous(_) => {
450 assert_ne!(total, Size::ZERO);
452 HomogeneousAggregate::NoData => {
453 assert_eq!(total, Size::ZERO);
463 /// Information about how to pass an argument to,
464 /// or return a value from, a function, under some ABI.
465 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
466 pub struct ArgAbi<'a, Ty> {
467 pub layout: TyAndLayout<'a, Ty>,
471 impl<'a, Ty> ArgAbi<'a, Ty> {
473 cx: &impl HasDataLayout,
474 layout: TyAndLayout<'a, Ty>,
475 scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes,
477 let mode = match layout.abi {
478 Abi::Uninhabited => PassMode::Ignore,
479 Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)),
480 Abi::ScalarPair(a, b) => PassMode::Pair(
481 scalar_attrs(&layout, a, Size::ZERO),
482 scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)),
484 Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
485 Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
487 ArgAbi { layout, mode }
490 fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode {
491 let mut attrs = ArgAttributes::new();
493 // For non-immediate arguments the callee gets its own copy of
494 // the value on the stack, so there are no aliases. It's also
495 // program-invisible so can't possibly capture
497 .set(ArgAttribute::NoAlias)
498 .set(ArgAttribute::NoCapture)
499 .set(ArgAttribute::NonNull)
500 .set(ArgAttribute::NoUndef);
501 attrs.pointee_size = layout.size;
502 // FIXME(eddyb) We should be doing this, but at least on
503 // i686-pc-windows-msvc, it results in wrong stack offsets.
504 // attrs.pointee_align = Some(layout.align.abi);
506 let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new());
508 PassMode::Indirect { attrs, extra_attrs, on_stack: false }
511 pub fn make_indirect(&mut self) {
513 PassMode::Direct(_) | PassMode::Pair(_, _) => {}
514 PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return,
515 _ => panic!("Tried to make {:?} indirect", self.mode),
518 self.mode = Self::indirect_pass_mode(&self.layout);
521 pub fn make_indirect_byval(&mut self) {
522 self.make_indirect();
524 PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => {
531 pub fn extend_integer_width_to(&mut self, bits: u64) {
532 // Only integers have signedness
533 if let Abi::Scalar(scalar) = self.layout.abi {
534 if let abi::Int(i, signed) = scalar.primitive() {
535 if i.size().bits() < bits {
536 if let PassMode::Direct(ref mut attrs) = self.mode {
538 attrs.ext(ArgExtension::Sext)
540 attrs.ext(ArgExtension::Zext)
548 pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
549 self.mode = PassMode::Cast(Box::new(target.into()), false);
552 pub fn cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool) {
553 self.mode = PassMode::Cast(Box::new(target.into()), pad_i32);
556 pub fn is_indirect(&self) -> bool {
557 matches!(self.mode, PassMode::Indirect { .. })
560 pub fn is_sized_indirect(&self) -> bool {
561 matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ })
564 pub fn is_unsized_indirect(&self) -> bool {
565 matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ })
568 pub fn is_ignore(&self) -> bool {
569 matches!(self.mode, PassMode::Ignore)
573 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
575 // General language calling conventions, for which every target
576 // should have its own backend (e.g. LLVM) support.
580 /// For things unlikely to be called, where smaller caller codegen is
581 /// preferred over raw speed.
582 /// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
585 // Target-specific calling conventions.
604 AvrNonBlockingInterrupt,
607 /// Metadata describing how the arguments to a native function
608 /// should be passed in order to respect the native ABI.
610 /// I will do my best to describe this structure, but these
611 /// comments are reverse-engineered and may be inaccurate. -NDM
612 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
613 pub struct FnAbi<'a, Ty> {
614 /// The LLVM types of each argument.
615 pub args: Box<[ArgAbi<'a, Ty>]>,
617 /// LLVM return type.
618 pub ret: ArgAbi<'a, Ty>,
620 pub c_variadic: bool,
622 /// The count of non-variadic arguments.
624 /// Should only be different from args.len() when c_variadic is true.
625 /// This can be used to know whether an argument is variadic or not.
626 pub fixed_count: u32,
630 pub can_unwind: bool,
633 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
634 #[derive(Copy, Clone, Debug, HashStable_Generic)]
635 pub enum AdjustForForeignAbiError {
636 /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
637 Unsupported { arch: Symbol, abi: spec::abi::Abi },
640 impl fmt::Display for AdjustForForeignAbiError {
641 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643 Self::Unsupported { arch, abi } => {
644 write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
650 impl<'a, Ty> FnAbi<'a, Ty> {
651 pub fn adjust_for_foreign_abi<C>(
655 ) -> Result<(), AdjustForForeignAbiError>
657 Ty: TyAbiInterface<'a, C> + Copy,
658 C: HasDataLayout + HasTargetSpec,
660 if abi == spec::abi::Abi::X86Interrupt {
661 if let Some(arg) = self.args.first_mut() {
662 arg.make_indirect_byval();
667 match &cx.target_spec().arch[..] {
669 let flavor = if let spec::abi::Abi::Fastcall { .. }
670 | spec::abi::Abi::Vectorcall { .. } = abi
672 x86::Flavor::FastcallOrVectorcall
676 x86::compute_abi_info(cx, self, flavor);
678 "x86_64" => match abi {
679 spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
680 spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self),
682 if cx.target_spec().is_like_windows {
683 x86_win64::compute_abi_info(self)
685 x86_64::compute_abi_info(cx, self)
690 let param_policy = if cx.target_spec().is_like_osx {
691 aarch64::ParamExtension::ExtendTo32Bits
693 aarch64::ParamExtension::NoExtension
695 aarch64::compute_abi_info(cx, self, param_policy)
697 "amdgpu" => amdgpu::compute_abi_info(cx, self),
698 "arm" => arm::compute_abi_info(cx, self),
699 "avr" => avr::compute_abi_info(self),
700 "loongarch64" => loongarch::compute_abi_info(cx, self),
701 "m68k" => m68k::compute_abi_info(self),
702 "mips" => mips::compute_abi_info(cx, self),
703 "mips64" => mips64::compute_abi_info(cx, self),
704 "powerpc" => powerpc::compute_abi_info(self),
705 "powerpc64" => powerpc64::compute_abi_info(cx, self),
706 "s390x" => s390x::compute_abi_info(cx, self),
707 "msp430" => msp430::compute_abi_info(self),
708 "sparc" => sparc::compute_abi_info(cx, self),
709 "sparc64" => sparc64::compute_abi_info(cx, self),
711 if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
712 nvptx64::compute_ptx_kernel_abi_info(cx, self)
714 nvptx64::compute_abi_info(self)
717 "hexagon" => hexagon::compute_abi_info(self),
718 "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
719 "wasm32" | "wasm64" => {
720 if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::Wasm {
721 wasm::compute_wasm_abi_info(self)
723 wasm::compute_c_abi_info(cx, self)
726 "asmjs" => wasm::compute_c_abi_info(cx, self),
727 "bpf" => bpf::compute_abi_info(self),
729 return Err(AdjustForForeignAbiError::Unsupported {
730 arch: Symbol::intern(arch),
740 // Some types are used a lot. Make sure they don't unintentionally get bigger.
741 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
744 use rustc_data_structures::static_assert_size;
745 // These are in alphabetical order, which is easy to maintain.
746 static_assert_size!(ArgAbi<'_, usize>, 56);
747 static_assert_size!(FnAbi<'_, usize>, 80);