about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/src/callconv.rs254
-rw-r--r--compiler/rustc_abi/src/layout.rs4
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs (renamed from compiler/rustc_target/src/abi/mod.rs)12
-rw-r--r--compiler/rustc_abi/src/lib.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs31
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_target/src/callconv/aarch64.rs (renamed from compiler/rustc_target/src/abi/call/aarch64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/amdgpu.rs (renamed from compiler/rustc_target/src/abi/call/amdgpu.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/arm.rs (renamed from compiler/rustc_target/src/abi/call/arm.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/avr.rs (renamed from compiler/rustc_target/src/abi/call/avr.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/bpf.rs (renamed from compiler/rustc_target/src/abi/call/bpf.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/csky.rs (renamed from compiler/rustc_target/src/abi/call/csky.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/hexagon.rs (renamed from compiler/rustc_target/src/abi/call/hexagon.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/loongarch.rs (renamed from compiler/rustc_target/src/abi/call/loongarch.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/m68k.rs (renamed from compiler/rustc_target/src/abi/call/m68k.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/mips.rs (renamed from compiler/rustc_target/src/abi/call/mips.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/mips64.rs (renamed from compiler/rustc_target/src/abi/call/mips64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs (renamed from compiler/rustc_target/src/abi/call/mod.rs)249
-rw-r--r--compiler/rustc_target/src/callconv/msp430.rs (renamed from compiler/rustc_target/src/abi/call/msp430.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/nvptx64.rs (renamed from compiler/rustc_target/src/abi/call/nvptx64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/powerpc.rs (renamed from compiler/rustc_target/src/abi/call/powerpc.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/powerpc64.rs (renamed from compiler/rustc_target/src/abi/call/powerpc64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/riscv.rs (renamed from compiler/rustc_target/src/abi/call/riscv.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/s390x.rs (renamed from compiler/rustc_target/src/abi/call/s390x.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/sparc.rs (renamed from compiler/rustc_target/src/abi/call/sparc.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/sparc64.rs (renamed from compiler/rustc_target/src/abi/call/sparc64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/wasm.rs (renamed from compiler/rustc_target/src/abi/call/wasm.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/x86.rs (renamed from compiler/rustc_target/src/abi/call/x86.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/x86_64.rs (renamed from compiler/rustc_target/src/abi/call/x86_64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/x86_win64.rs (renamed from compiler/rustc_target/src/abi/call/x86_win64.rs)0
-rw-r--r--compiler/rustc_target/src/callconv/xtensa.rs (renamed from compiler/rustc_target/src/abi/call/xtensa.rs)0
-rw-r--r--compiler/rustc_target/src/json.rs6
-rw-r--r--compiler/rustc_target/src/lib.rs11
35 files changed, 306 insertions, 283 deletions
diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs
new file mode 100644
index 00000000000..2ecac8a9df1
--- /dev/null
+++ b/compiler/rustc_abi/src/callconv.rs
@@ -0,0 +1,254 @@
+mod abi {
+    pub(crate) use crate::Primitive::*;
+    pub(crate) use crate::Variants;
+}
+
+use rustc_macros::HashStable_Generic;
+
+use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+pub enum RegKind {
+    Integer,
+    Float,
+    Vector,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+pub struct Reg {
+    pub kind: RegKind,
+    pub size: Size,
+}
+
+macro_rules! reg_ctor {
+    ($name:ident, $kind:ident, $bits:expr) => {
+        pub fn $name() -> Reg {
+            Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
+        }
+    };
+}
+
+impl Reg {
+    reg_ctor!(i8, Integer, 8);
+    reg_ctor!(i16, Integer, 16);
+    reg_ctor!(i32, Integer, 32);
+    reg_ctor!(i64, Integer, 64);
+    reg_ctor!(i128, Integer, 128);
+
+    reg_ctor!(f32, Float, 32);
+    reg_ctor!(f64, Float, 64);
+}
+
+impl Reg {
+    pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
+        let dl = cx.data_layout();
+        match self.kind {
+            RegKind::Integer => match self.size.bits() {
+                1 => dl.i1_align.abi,
+                2..=8 => dl.i8_align.abi,
+                9..=16 => dl.i16_align.abi,
+                17..=32 => dl.i32_align.abi,
+                33..=64 => dl.i64_align.abi,
+                65..=128 => dl.i128_align.abi,
+                _ => panic!("unsupported integer: {self:?}"),
+            },
+            RegKind::Float => match self.size.bits() {
+                16 => dl.f16_align.abi,
+                32 => dl.f32_align.abi,
+                64 => dl.f64_align.abi,
+                128 => dl.f128_align.abi,
+                _ => panic!("unsupported float: {self:?}"),
+            },
+            RegKind::Vector => dl.vector_align(self.size).abi,
+        }
+    }
+}
+
+/// Return value from the `homogeneous_aggregate` test function.
+#[derive(Copy, Clone, Debug)]
+pub enum HomogeneousAggregate {
+    /// Yes, all the "leaf fields" of this struct are passed in the
+    /// same way (specified in the `Reg` value).
+    Homogeneous(Reg),
+
+    /// There are no leaf fields at all.
+    NoData,
+}
+
+/// Error from the `homogeneous_aggregate` test function, indicating
+/// there are distinct leaf fields passed in different ways,
+/// or this is uninhabited.
+#[derive(Copy, Clone, Debug)]
+pub struct Heterogeneous;
+
+impl HomogeneousAggregate {
+    /// If this is a homogeneous aggregate, returns the homogeneous
+    /// unit, else `None`.
+    pub fn unit(self) -> Option<Reg> {
+        match self {
+            HomogeneousAggregate::Homogeneous(reg) => Some(reg),
+            HomogeneousAggregate::NoData => None,
+        }
+    }
+
+    /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
+    /// the same `struct`. Only succeeds if only one of them has any data,
+    /// or both units are identical.
+    fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
+        match (self, other) {
+            (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
+
+            (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
+                if a != b {
+                    return Err(Heterogeneous);
+                }
+                Ok(self)
+            }
+        }
+    }
+}
+
+impl<'a, Ty> TyAndLayout<'a, Ty> {
+    /// Returns `true` if this is an aggregate type (including a ScalarPair!)
+    pub fn is_aggregate(&self) -> bool {
+        match self.abi {
+            Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
+            Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
+        }
+    }
+
+    /// Returns `Homogeneous` if this layout is an aggregate containing fields of
+    /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
+    /// special-cased in ABIs.
+    ///
+    /// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
+    ///
+    /// This is public so that it can be used in unit tests, but
+    /// should generally only be relevant to the ABI details of
+    /// specific targets.
+    pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
+    where
+        Ty: TyAbiInterface<'a, C> + Copy,
+    {
+        match self.abi {
+            Abi::Uninhabited => Err(Heterogeneous),
+
+            // The primitive for this algorithm.
+            Abi::Scalar(scalar) => {
+                let kind = match scalar.primitive() {
+                    abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
+                    abi::Float(_) => RegKind::Float,
+                };
+                Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
+            }
+
+            Abi::Vector { .. } => {
+                assert!(!self.is_zst());
+                Ok(HomogeneousAggregate::Homogeneous(Reg {
+                    kind: RegKind::Vector,
+                    size: self.size,
+                }))
+            }
+
+            Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => {
+                // Helper for computing `homogeneous_aggregate`, allowing a custom
+                // starting offset (used below for handling variants).
+                let from_fields_at =
+                    |layout: Self,
+                     start: Size|
+                     -> Result<(HomogeneousAggregate, Size), Heterogeneous> {
+                        let is_union = match layout.fields {
+                            FieldsShape::Primitive => {
+                                unreachable!("aggregates can't have `FieldsShape::Primitive`")
+                            }
+                            FieldsShape::Array { count, .. } => {
+                                assert_eq!(start, Size::ZERO);
+
+                                let result = if count > 0 {
+                                    layout.field(cx, 0).homogeneous_aggregate(cx)?
+                                } else {
+                                    HomogeneousAggregate::NoData
+                                };
+                                return Ok((result, layout.size));
+                            }
+                            FieldsShape::Union(_) => true,
+                            FieldsShape::Arbitrary { .. } => false,
+                        };
+
+                        let mut result = HomogeneousAggregate::NoData;
+                        let mut total = start;
+
+                        for i in 0..layout.fields.count() {
+                            let field = layout.field(cx, i);
+                            if field.is_1zst() {
+                                // No data here and no impact on layout, can be ignored.
+                                // (We might be able to also ignore all aligned ZST but that's less clear.)
+                                continue;
+                            }
+
+                            if !is_union && total != layout.fields.offset(i) {
+                                // This field isn't just after the previous one we considered, abort.
+                                return Err(Heterogeneous);
+                            }
+
+                            result = result.merge(field.homogeneous_aggregate(cx)?)?;
+
+                            // Keep track of the offset (without padding).
+                            let size = field.size;
+                            if is_union {
+                                total = total.max(size);
+                            } else {
+                                total += size;
+                            }
+                        }
+
+                        Ok((result, total))
+                    };
+
+                let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
+
+                match &self.variants {
+                    abi::Variants::Single { .. } => {}
+                    abi::Variants::Multiple { variants, .. } => {
+                        // Treat enum variants like union members.
+                        // HACK(eddyb) pretend the `enum` field (discriminant)
+                        // is at the start of every variant (otherwise the gap
+                        // at the start of all variants would disqualify them).
+                        //
+                        // NB: for all tagged `enum`s (which include all non-C-like
+                        // `enum`s with defined FFI representation), this will
+                        // match the homogeneous computation on the equivalent
+                        // `struct { tag; union { variant1; ... } }` and/or
+                        // `union { struct { tag; variant1; } ... }`
+                        // (the offsets of variant fields should be identical
+                        // between the two for either to be a homogeneous aggregate).
+                        let variant_start = total;
+                        for variant_idx in variants.indices() {
+                            let (variant_result, variant_total) =
+                                from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
+
+                            result = result.merge(variant_result)?;
+                            total = total.max(variant_total);
+                        }
+                    }
+                }
+
+                // There needs to be no padding.
+                if total != self.size {
+                    Err(Heterogeneous)
+                } else {
+                    match result {
+                        HomogeneousAggregate::Homogeneous(_) => {
+                            assert_ne!(total, Size::ZERO);
+                        }
+                        HomogeneousAggregate::NoData => {
+                            assert_eq!(total, Size::ZERO);
+                        }
+                    }
+                    Ok(result)
+                }
+            }
+            Abi::Aggregate { sized: false } => Err(Heterogeneous),
+        }
+    }
+}
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 620a051eeb7..6e1299944a0 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -11,6 +11,10 @@ use crate::{
     Variants, WrappingRange,
 };
 
+mod ty;
+
+pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
+
 // A variant is absent if it's uninhabited and only has ZST fields.
 // Present uninhabited variants only require space for their fields,
 // but *not* an encoding of the discriminant (e.g., a tag value).
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_abi/src/layout/ty.rs
index b744d5ad4ed..c6812c4d4c0 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -6,18 +6,8 @@ use Primitive::*;
 use rustc_data_structures::intern::Interned;
 use rustc_macros::HashStable_Generic;
 
-use crate::json::{Json, ToJson};
-
-pub mod call;
-
 // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
-pub use rustc_abi::{Float, *};
-
-impl ToJson for Endian {
-    fn to_json(&self) -> Json {
-        self.as_str().to_json()
-    }
-}
+use crate::{Float, *};
 
 rustc_index::newtype_index! {
     /// The *source-order* index of a field in a variant.
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index fa7c98a7fa0..84d756b6d51 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,6 +1,7 @@
 // tidy-alphabetical-start
 #![cfg_attr(feature = "nightly", allow(internal_features))]
 #![cfg_attr(feature = "nightly", doc(rust_logo))]
+#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
 #![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
 #![cfg_attr(feature = "nightly", feature(step_trait))]
 #![warn(unreachable_pub)]
@@ -22,11 +23,16 @@ use rustc_macros::HashStable_Generic;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_Generic, Encodable_Generic};
 
+mod callconv;
 mod layout;
 #[cfg(test)]
 mod tests;
 
-pub use layout::{LayoutCalculator, LayoutCalculatorError};
+pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
+pub use layout::{
+    FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
+    TyAndLayout, VariantIdx,
+};
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 263e4a9379f..365924ef782 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1327,14 +1327,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             // takes care of rejecting invalid modifier combinations and
                             // const trait bounds in trait object types.
                             GenericBound::Trait(ty, modifiers) => {
-                                // Still, don't pass along the constness here; we don't want to
-                                // synthesize any host effect args, it'd only cause problems.
-                                let modifiers = TraitBoundModifiers {
-                                    constness: BoundConstness::Never,
-                                    ..*modifiers
-                                };
-                                let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers);
-                                let polarity = this.lower_trait_bound_modifiers(modifiers);
+                                let trait_ref = this.lower_poly_trait_ref(ty, itctx, *modifiers);
+                                let polarity = this.lower_trait_bound_modifiers(*modifiers);
                                 Some((trait_ref, polarity))
                             }
                             GenericBound::Outlives(lifetime) => {
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 4aec74595bc..2db43a0f787 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -140,7 +140,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
 
     #[inline(always)]
     fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
-        self.iter().filter_map(move |(k, v)| f(k, &*v)).collect()
+        self.iter().filter_map(move |(k, v)| f(k, v)).collect()
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index e6ab8ca12a8..7700eb792ef 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -993,11 +993,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         bytes
     }
 
-    /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation
-    /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true.
-    pub fn find_leaked_allocations(
-        &self,
-        static_roots: &[AllocId],
+    /// Find leaked allocations, remove them from memory and return them. Allocations reachable from
+    /// `static_roots` or a `Global` allocation are not considered leaked, as well as leaks whose
+    /// kind's `may_leak()` returns true.
+    ///
+    /// This is highly destructive, no more execution can happen after this!
+    pub fn take_leaked_allocations(
+        &mut self,
+        static_roots: impl FnOnce(&Self) -> &[AllocId],
     ) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)>
     {
         // Collect the set of allocations that are *reachable* from `Global` allocations.
@@ -1008,7 +1011,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.memory.alloc_map.filter_map_collect(move |&id, &(kind, _)| {
                     if Some(kind) == global_kind { Some(id) } else { None }
                 });
-            todo.extend(static_roots);
+            todo.extend(static_roots(self));
             while let Some(id) = todo.pop() {
                 if reachable.insert(id) {
                     // This is a new allocation, add the allocation it points to `todo`.
@@ -1023,13 +1026,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         };
 
         // All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking.
-        self.memory.alloc_map.filter_map_collect(|id, (kind, alloc)| {
-            if kind.may_leak() || reachable.contains(id) {
-                None
-            } else {
-                Some((*id, *kind, alloc.clone()))
-            }
-        })
+        let leaked: Vec<_> = self.memory.alloc_map.filter_map_collect(|&id, &(kind, _)| {
+            if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) }
+        });
+        let mut result = Vec::new();
+        for &id in leaked.iter() {
+            let (kind, alloc) = self.memory.alloc_map.remove(&id).unwrap();
+            result.push((id, kind, alloc));
+        }
+        result
     }
 
     /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 50e7be82a79..1bdcae4dfb4 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -12,6 +12,7 @@ use std::marker::PhantomData;
 use std::ops::{Bound, Deref};
 use std::{fmt, iter, mem};
 
+use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_ast::{self as ast, attr};
 use rustc_data_structures::defer;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -48,7 +49,6 @@ use rustc_session::{Limit, MetadataKind, Session};
 use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
 use rustc_span::symbol::{Ident, Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, Span};
-use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::fold::TypeFoldable;
diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs
index 55b65fb1caa..55b65fb1caa 100644
--- a/compiler/rustc_target/src/abi/call/aarch64.rs
+++ b/compiler/rustc_target/src/callconv/aarch64.rs
diff --git a/compiler/rustc_target/src/abi/call/amdgpu.rs b/compiler/rustc_target/src/callconv/amdgpu.rs
index 3007a729a8b..3007a729a8b 100644
--- a/compiler/rustc_target/src/abi/call/amdgpu.rs
+++ b/compiler/rustc_target/src/callconv/amdgpu.rs
diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/callconv/arm.rs
index bd6f781fb81..bd6f781fb81 100644
--- a/compiler/rustc_target/src/abi/call/arm.rs
+++ b/compiler/rustc_target/src/callconv/arm.rs
diff --git a/compiler/rustc_target/src/abi/call/avr.rs b/compiler/rustc_target/src/callconv/avr.rs
index dfc991e0954..dfc991e0954 100644
--- a/compiler/rustc_target/src/abi/call/avr.rs
+++ b/compiler/rustc_target/src/callconv/avr.rs
diff --git a/compiler/rustc_target/src/abi/call/bpf.rs b/compiler/rustc_target/src/callconv/bpf.rs
index f19772ac709..f19772ac709 100644
--- a/compiler/rustc_target/src/abi/call/bpf.rs
+++ b/compiler/rustc_target/src/callconv/bpf.rs
diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/callconv/csky.rs
index b1c1ae814a7..b1c1ae814a7 100644
--- a/compiler/rustc_target/src/abi/call/csky.rs
+++ b/compiler/rustc_target/src/callconv/csky.rs
diff --git a/compiler/rustc_target/src/abi/call/hexagon.rs b/compiler/rustc_target/src/callconv/hexagon.rs
index 0a0688880c0..0a0688880c0 100644
--- a/compiler/rustc_target/src/abi/call/hexagon.rs
+++ b/compiler/rustc_target/src/callconv/hexagon.rs
diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index 4a21935623b..4a21935623b 100644
--- a/compiler/rustc_target/src/abi/call/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
diff --git a/compiler/rustc_target/src/abi/call/m68k.rs b/compiler/rustc_target/src/callconv/m68k.rs
index 82fe81f8c52..82fe81f8c52 100644
--- a/compiler/rustc_target/src/abi/call/m68k.rs
+++ b/compiler/rustc_target/src/callconv/m68k.rs
diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/callconv/mips.rs
index 37980a91c76..37980a91c76 100644
--- a/compiler/rustc_target/src/abi/call/mips.rs
+++ b/compiler/rustc_target/src/callconv/mips.rs
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs
index 2c3258c8d42..2c3258c8d42 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/callconv/mips64.rs
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 352861c5ccb..832246495bc 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -1,10 +1,11 @@
 use std::fmt;
 use std::str::FromStr;
 
+pub use rustc_abi::{Reg, RegKind};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
-use crate::abi::{self, Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
 use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
 
 mod aarch64;
@@ -192,63 +193,6 @@ impl ArgAttributes {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum RegKind {
-    Integer,
-    Float,
-    Vector,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub struct Reg {
-    pub kind: RegKind,
-    pub size: Size,
-}
-
-macro_rules! reg_ctor {
-    ($name:ident, $kind:ident, $bits:expr) => {
-        pub fn $name() -> Reg {
-            Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
-        }
-    };
-}
-
-impl Reg {
-    reg_ctor!(i8, Integer, 8);
-    reg_ctor!(i16, Integer, 16);
-    reg_ctor!(i32, Integer, 32);
-    reg_ctor!(i64, Integer, 64);
-    reg_ctor!(i128, Integer, 128);
-
-    reg_ctor!(f32, Float, 32);
-    reg_ctor!(f64, Float, 64);
-}
-
-impl Reg {
-    pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
-        let dl = cx.data_layout();
-        match self.kind {
-            RegKind::Integer => match self.size.bits() {
-                1 => dl.i1_align.abi,
-                2..=8 => dl.i8_align.abi,
-                9..=16 => dl.i16_align.abi,
-                17..=32 => dl.i32_align.abi,
-                33..=64 => dl.i64_align.abi,
-                65..=128 => dl.i128_align.abi,
-                _ => panic!("unsupported integer: {self:?}"),
-            },
-            RegKind::Float => match self.size.bits() {
-                16 => dl.f16_align.abi,
-                32 => dl.f32_align.abi,
-                64 => dl.f64_align.abi,
-                128 => dl.f128_align.abi,
-                _ => panic!("unsupported float: {self:?}"),
-            },
-            RegKind::Vector => dl.vector_align(self.size).abi,
-        }
-    }
-}
-
 /// An argument passed entirely registers with the
 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
@@ -380,195 +324,6 @@ impl CastTarget {
     }
 }
 
-/// Return value from the `homogeneous_aggregate` test function.
-#[derive(Copy, Clone, Debug)]
-pub enum HomogeneousAggregate {
-    /// Yes, all the "leaf fields" of this struct are passed in the
-    /// same way (specified in the `Reg` value).
-    Homogeneous(Reg),
-
-    /// There are no leaf fields at all.
-    NoData,
-}
-
-/// Error from the `homogeneous_aggregate` test function, indicating
-/// there are distinct leaf fields passed in different ways,
-/// or this is uninhabited.
-#[derive(Copy, Clone, Debug)]
-pub struct Heterogeneous;
-
-impl HomogeneousAggregate {
-    /// If this is a homogeneous aggregate, returns the homogeneous
-    /// unit, else `None`.
-    pub fn unit(self) -> Option<Reg> {
-        match self {
-            HomogeneousAggregate::Homogeneous(reg) => Some(reg),
-            HomogeneousAggregate::NoData => None,
-        }
-    }
-
-    /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
-    /// the same `struct`. Only succeeds if only one of them has any data,
-    /// or both units are identical.
-    fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
-        match (self, other) {
-            (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
-
-            (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
-                if a != b {
-                    return Err(Heterogeneous);
-                }
-                Ok(self)
-            }
-        }
-    }
-}
-
-impl<'a, Ty> TyAndLayout<'a, Ty> {
-    /// Returns `true` if this is an aggregate type (including a ScalarPair!)
-    fn is_aggregate(&self) -> bool {
-        match self.abi {
-            Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
-            Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
-        }
-    }
-
-    /// Returns `Homogeneous` if this layout is an aggregate containing fields of
-    /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
-    /// special-cased in ABIs.
-    ///
-    /// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
-    ///
-    /// This is public so that it can be used in unit tests, but
-    /// should generally only be relevant to the ABI details of
-    /// specific targets.
-    pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
-    where
-        Ty: TyAbiInterface<'a, C> + Copy,
-    {
-        match self.abi {
-            Abi::Uninhabited => Err(Heterogeneous),
-
-            // The primitive for this algorithm.
-            Abi::Scalar(scalar) => {
-                let kind = match scalar.primitive() {
-                    abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
-                    abi::Float(_) => RegKind::Float,
-                };
-                Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
-            }
-
-            Abi::Vector { .. } => {
-                assert!(!self.is_zst());
-                Ok(HomogeneousAggregate::Homogeneous(Reg {
-                    kind: RegKind::Vector,
-                    size: self.size,
-                }))
-            }
-
-            Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => {
-                // Helper for computing `homogeneous_aggregate`, allowing a custom
-                // starting offset (used below for handling variants).
-                let from_fields_at =
-                    |layout: Self,
-                     start: Size|
-                     -> Result<(HomogeneousAggregate, Size), Heterogeneous> {
-                        let is_union = match layout.fields {
-                            FieldsShape::Primitive => {
-                                unreachable!("aggregates can't have `FieldsShape::Primitive`")
-                            }
-                            FieldsShape::Array { count, .. } => {
-                                assert_eq!(start, Size::ZERO);
-
-                                let result = if count > 0 {
-                                    layout.field(cx, 0).homogeneous_aggregate(cx)?
-                                } else {
-                                    HomogeneousAggregate::NoData
-                                };
-                                return Ok((result, layout.size));
-                            }
-                            FieldsShape::Union(_) => true,
-                            FieldsShape::Arbitrary { .. } => false,
-                        };
-
-                        let mut result = HomogeneousAggregate::NoData;
-                        let mut total = start;
-
-                        for i in 0..layout.fields.count() {
-                            let field = layout.field(cx, i);
-                            if field.is_1zst() {
-                                // No data here and no impact on layout, can be ignored.
-                                // (We might be able to also ignore all aligned ZST but that's less clear.)
-                                continue;
-                            }
-
-                            if !is_union && total != layout.fields.offset(i) {
-                                // This field isn't just after the previous one we considered, abort.
-                                return Err(Heterogeneous);
-                            }
-
-                            result = result.merge(field.homogeneous_aggregate(cx)?)?;
-
-                            // Keep track of the offset (without padding).
-                            let size = field.size;
-                            if is_union {
-                                total = total.max(size);
-                            } else {
-                                total += size;
-                            }
-                        }
-
-                        Ok((result, total))
-                    };
-
-                let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
-
-                match &self.variants {
-                    abi::Variants::Single { .. } => {}
-                    abi::Variants::Multiple { variants, .. } => {
-                        // Treat enum variants like union members.
-                        // HACK(eddyb) pretend the `enum` field (discriminant)
-                        // is at the start of every variant (otherwise the gap
-                        // at the start of all variants would disqualify them).
-                        //
-                        // NB: for all tagged `enum`s (which include all non-C-like
-                        // `enum`s with defined FFI representation), this will
-                        // match the homogeneous computation on the equivalent
-                        // `struct { tag; union { variant1; ... } }` and/or
-                        // `union { struct { tag; variant1; } ... }`
-                        // (the offsets of variant fields should be identical
-                        // between the two for either to be a homogeneous aggregate).
-                        let variant_start = total;
-                        for variant_idx in variants.indices() {
-                            let (variant_result, variant_total) =
-                                from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
-
-                            result = result.merge(variant_result)?;
-                            total = total.max(variant_total);
-                        }
-                    }
-                }
-
-                // There needs to be no padding.
-                if total != self.size {
-                    Err(Heterogeneous)
-                } else {
-                    match result {
-                        HomogeneousAggregate::Homogeneous(_) => {
-                            assert_ne!(total, Size::ZERO);
-                        }
-                        HomogeneousAggregate::NoData => {
-                            assert_eq!(total, Size::ZERO);
-                        }
-                    }
-                    Ok(result)
-                }
-            }
-            Abi::Aggregate { sized: false } => Err(Heterogeneous),
-        }
-    }
-}
-
 /// Information about how to pass an argument to,
 /// or return a value from, a function, under some ABI.
 #[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
diff --git a/compiler/rustc_target/src/abi/call/msp430.rs b/compiler/rustc_target/src/callconv/msp430.rs
index 4f613aa6c15..4f613aa6c15 100644
--- a/compiler/rustc_target/src/abi/call/msp430.rs
+++ b/compiler/rustc_target/src/callconv/msp430.rs
diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs
index 2e8b16d3a93..2e8b16d3a93 100644
--- a/compiler/rustc_target/src/abi/call/nvptx64.rs
+++ b/compiler/rustc_target/src/callconv/nvptx64.rs
diff --git a/compiler/rustc_target/src/abi/call/powerpc.rs b/compiler/rustc_target/src/callconv/powerpc.rs
index f3b05c48173..f3b05c48173 100644
--- a/compiler/rustc_target/src/abi/call/powerpc.rs
+++ b/compiler/rustc_target/src/callconv/powerpc.rs
diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs
index 71e533b8cc5..71e533b8cc5 100644
--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
+++ b/compiler/rustc_target/src/callconv/powerpc64.rs
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index be6bc701b49..be6bc701b49 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs
index 502e7331267..502e7331267 100644
--- a/compiler/rustc_target/src/abi/call/s390x.rs
+++ b/compiler/rustc_target/src/callconv/s390x.rs
diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs
index 37980a91c76..37980a91c76 100644
--- a/compiler/rustc_target/src/abi/call/sparc.rs
+++ b/compiler/rustc_target/src/callconv/sparc.rs
diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs
index 835353f76fc..835353f76fc 100644
--- a/compiler/rustc_target/src/abi/call/sparc64.rs
+++ b/compiler/rustc_target/src/callconv/sparc64.rs
diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs
index 3c4cd76a754..3c4cd76a754 100644
--- a/compiler/rustc_target/src/abi/call/wasm.rs
+++ b/compiler/rustc_target/src/callconv/wasm.rs
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index d9af83d3205..d9af83d3205 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs
index 9910e623ac9..9910e623ac9 100644
--- a/compiler/rustc_target/src/abi/call/x86_64.rs
+++ b/compiler/rustc_target/src/callconv/x86_64.rs
diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs
index e5a20b248e4..e5a20b248e4 100644
--- a/compiler/rustc_target/src/abi/call/x86_win64.rs
+++ b/compiler/rustc_target/src/callconv/x86_win64.rs
diff --git a/compiler/rustc_target/src/abi/call/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs
index e1728b08a39..e1728b08a39 100644
--- a/compiler/rustc_target/src/abi/call/xtensa.rs
+++ b/compiler/rustc_target/src/callconv/xtensa.rs
diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs
index 2c367defe7b..b09d8d724ef 100644
--- a/compiler/rustc_target/src/json.rs
+++ b/compiler/rustc_target/src/json.rs
@@ -134,3 +134,9 @@ impl ToJson for TargetMetadata {
         })
     }
 }
+
+impl ToJson for rustc_abi::Endian {
+    fn to_json(&self) -> Json {
+        self.as_str().to_json()
+    }
+}
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 2121c4110dd..50679ab8cc8 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -21,8 +21,8 @@
 
 use std::path::{Path, PathBuf};
 
-pub mod abi;
 pub mod asm;
+pub mod callconv;
 pub mod json;
 pub mod spec;
 pub mod target_features;
@@ -30,6 +30,15 @@ pub mod target_features;
 #[cfg(test)]
 mod tests;
 
+pub mod abi {
+    pub(crate) use Float::*;
+    pub(crate) use Primitive::*;
+    // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
+    pub use rustc_abi::{Float, *};
+
+    pub use crate::callconv as call;
+}
+
 pub use rustc_abi::HashStableContext;
 
 /// The name of rustc's own place to organize libraries.