From f5c39679c6d87e0960c628cba6fe16dd0373443c Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen@gmail.com>
Date: Sat, 16 Dec 2023 20:37:57 +0000
Subject: [PATCH 1/5] std::net::bind using -1 for openbsd which in turn sets it
 to somaxconn.

trusting platform's SOMAXCONN instead of hardcoding to 128 otherwise.
---
 library/std/src/os/unix/net/listener.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index 5be8aebc70fd5..679a6f1a3c3ae 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -74,7 +74,11 @@ impl UnixListener {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
             const backlog: libc::c_int =
-                if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 };
+                if cfg!(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")) {
+                    -1
+                } else {
+                    libc::SOMAXCONN
+                };
 
             cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
             cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;

From 1a83c5b55bdad84baca69d121d9c3e6f357e8570 Mon Sep 17 00:00:00 2001
From: "Celina G. Val" <celinval@amazon.com>
Date: Mon, 18 Dec 2023 19:52:25 +0000
Subject: [PATCH 2/5] Add function ABI and type layout to StableMIR

This change introduces a new module to StableMIR named `abi` with
information from `rustc_target::abi` and `rustc_abi`, that allow users
to retrieve more low level information required to perform
bit-precise analysis.

The layout of a type can be retrieved via `Ty::layout`, and the instance
ABI can be retrieved via `Instance::fn_abi()`.

To properly handle errors while retrieve layout information, we had
to implement a few layout related traits.
---
 .../rustc_smir/src/rustc_internal/internal.rs |   9 +
 compiler/rustc_smir/src/rustc_internal/mod.rs |   6 +
 compiler/rustc_smir/src/rustc_smir/context.rs |  75 ++++-
 .../rustc_smir/src/rustc_smir/convert/abi.rs  | 229 ++++++++++++++
 .../rustc_smir/src/rustc_smir/convert/mod.rs  |  20 +-
 compiler/rustc_smir/src/rustc_smir/mod.rs     |  13 +
 compiler/stable_mir/src/abi.rs                | 286 ++++++++++++++++++
 compiler/stable_mir/src/compiler_interface.rs |  10 +
 compiler/stable_mir/src/lib.rs                |   1 +
 compiler/stable_mir/src/mir/mono.rs           |   6 +
 compiler/stable_mir/src/ty.rs                 |   6 +
 .../stable-mir/check_allocation.rs            |   1 -
 tests/ui-fulldeps/stable-mir/check_defs.rs    |   6 +-
 tests/ui-fulldeps/stable-mir/check_layout.rs  | 117 +++++++
 14 files changed, 760 insertions(+), 25 deletions(-)
 create mode 100644 compiler/rustc_smir/src/rustc_smir/convert/abi.rs
 create mode 100644 compiler/stable_mir/src/abi.rs
 create mode 100644 tests/ui-fulldeps/stable-mir/check_layout.rs

diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 632072003539f..bbc98af45c0d7 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -7,6 +7,7 @@
 use crate::rustc_smir::Tables;
 use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
 use rustc_span::Symbol;
+use stable_mir::abi::Layout;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
 use stable_mir::mir::{Mutability, Safety};
@@ -460,6 +461,14 @@ impl<'tcx> RustcInternal<'tcx> for Span {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for Layout {
+    type T = rustc_target::abi::Layout<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.layouts[*self]
+    }
+}
+
 impl<'tcx, T> RustcInternal<'tcx> for &T
 where
     T: RustcInternal<'tcx>,
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index c3db9b358e8b5..4bac98909add0 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
 use scoped_tls::scoped_thread_local;
+use stable_mir::abi::Layout;
 use stable_mir::ty::IndexedVal;
 use stable_mir::Error;
 use std::cell::Cell;
@@ -136,6 +137,10 @@ impl<'tcx> Tables<'tcx> {
     pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
         stable_mir::mir::mono::StaticDef(self.create_def_id(did))
     }
+
+    pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout {
+        self.layouts.create_or_fetch(layout)
+    }
 }
 
 pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
@@ -180,6 +185,7 @@ where
         types: IndexMap::default(),
         instances: IndexMap::default(),
         constants: IndexMap::default(),
+        layouts: IndexMap::default(),
     }));
     stable_mir::compiler_interface::run(&tables, || init(&tables, f))
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 2361a04a6d7c2..621766c695e43 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -3,12 +3,19 @@
 //! This trait is currently the main interface between the Rust compiler,
 //! and the `stable_mir` crate.
 
+#![allow(rustc::usage_of_qualified_ty)]
+
+use rustc_abi::HasDataLayout;
 use rustc_middle::ty;
+use rustc_middle::ty::layout::{
+    FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers,
+};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    GenericPredicates, Instance, ParamEnv, ScalarInt, TypeVisitableExt, ValTree,
+    GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
 };
 use rustc_span::def_id::LOCAL_CRATE;
+use stable_mir::abi::{FnAbi, Layout, LayoutShape};
 use stable_mir::compiler_interface::Context;
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
@@ -280,7 +287,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
     }
 
-    #[allow(rustc::usage_of_qualified_ty)]
     fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
         let mut tables = self.0.borrow_mut();
         let inner = ty.internal(&mut *tables);
@@ -335,6 +341,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables)
     }
 
+    fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
+    }
+
     fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
         let mut tables = self.0.borrow_mut();
         let def_id = tables.instances[def].def_id();
@@ -473,6 +485,65 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
             )
         }
     }
+
+    fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
+        let mut tables = self.0.borrow_mut();
+        let ty = ty.internal(&mut *tables);
+        let layout = tables.layout_of(ty)?.layout;
+        Ok(layout.stable(&mut *tables))
+    }
+
+    fn layout_shape(&self, id: Layout) -> LayoutShape {
+        let mut tables = self.0.borrow_mut();
+        id.internal(&mut *tables).0.stable(&mut *tables)
+    }
 }
 
 pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
+
+/// Implement error handling for extracting function ABI information.
+impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
+    type FnAbiOfResult = Result<&'tcx rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: ty::layout::FnAbiError<'tcx>,
+        _span: rustc_span::Span,
+        fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
+    ) -> Error {
+        Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
+    }
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
+    type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, Error>;
+
+    #[inline]
+    fn handle_layout_err(
+        &self,
+        err: ty::layout::LayoutError<'tcx>,
+        _span: rustc_span::Span,
+        ty: ty::Ty<'tcx>,
+    ) -> Error {
+        Error::new(format!("Failed to get layout for `{ty}`: {err}"))
+    }
+}
+
+impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        ty::ParamEnv::reveal_all()
+    }
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'tcx> HasDataLayout for Tables<'tcx> {
+    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
+        self.tcx.data_layout()
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
new file mode 100644
index 0000000000000..46ae0929bcd4a
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -0,0 +1,229 @@
+//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones.
+
+#![allow(rustc::usage_of_qualified_ty)]
+
+use crate::rustc_smir::{Stable, Tables};
+use rustc_middle::ty;
+use rustc_target::abi::call::Conv;
+use stable_mir::abi::{
+    ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
+    TyAndLayout, ValueAbi, VariantsShape,
+};
+use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
+use stable_mir::{opaque, Opaque};
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
+    type T = VariantIdx;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        VariantIdx::to_val(self.as_usize())
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
+    type T = stable_mir::target::Endian;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
+            rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
+    type T = TyAndLayout;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
+    type T = Layout;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.layout_id(*self)
+    }
+}
+
+impl<'tcx> Stable<'tcx>
+    for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
+{
+    type T = LayoutShape;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        LayoutShape {
+            fields: self.fields.stable(tables),
+            variants: self.variants.stable(tables),
+            abi: self.abi.stable(tables),
+            abi_align: self.align.abi.stable(tables),
+            size: self.size.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
+    type T = FnAbi;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        FnAbi {
+            args: self.args.as_ref().stable(tables),
+            ret: self.ret.stable(tables),
+            fixed_count: self.fixed_count,
+            conv: self.conv.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
+    type T = ArgAbi;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        ArgAbi {
+            ty: self.layout.ty.stable(tables),
+            layout: self.layout.layout.stable(tables),
+            mode: self.mode.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
+    type T = CallConvention;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            Conv::C => CallConvention::C,
+            Conv::Rust => CallConvention::Rust,
+            Conv::Cold => CallConvention::Cold,
+            Conv::PreserveMost => CallConvention::PreserveMost,
+            Conv::PreserveAll => CallConvention::PreserveAll,
+            Conv::ArmAapcs => CallConvention::ArmAapcs,
+            Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
+            Conv::Msp430Intr => CallConvention::Msp430Intr,
+            Conv::PtxKernel => CallConvention::PtxKernel,
+            Conv::X86Fastcall => CallConvention::X86Fastcall,
+            Conv::X86Intr => CallConvention::X86Intr,
+            Conv::X86Stdcall => CallConvention::X86Stdcall,
+            Conv::X86ThisCall => CallConvention::X86ThisCall,
+            Conv::X86VectorCall => CallConvention::X86VectorCall,
+            Conv::X86_64SysV => CallConvention::X86_64SysV,
+            Conv::X86_64Win64 => CallConvention::X86_64Win64,
+            Conv::AmdGpuKernel => CallConvention::AmdGpuKernel,
+            Conv::AvrInterrupt => CallConvention::AvrInterrupt,
+            Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt,
+            Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
+    type T = PassMode;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
+            rustc_target::abi::call::PassMode::Direct(_) => PassMode::Direct,
+            rustc_target::abi::call::PassMode::Pair(_, _) => PassMode::Pair,
+            rustc_target::abi::call::PassMode::Cast { .. } => PassMode::Cast,
+            rustc_target::abi::call::PassMode::Indirect { .. } => PassMode::Indirect,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
+    type T = FieldsShape;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive,
+            rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count),
+            rustc_abi::FieldsShape::Array { stride, count } => {
+                FieldsShape::Array { stride: stride.stable(tables), count: *count }
+            }
+            rustc_abi::FieldsShape::Arbitrary { offsets, .. } => {
+                FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx>
+    for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
+{
+    type T = VariantsShape;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::Variants::Single { index } => {
+                VariantsShape::Single { index: index.stable(tables) }
+            }
+            rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => {
+                VariantsShape::Multiple {
+                    tag: tag.stable(tables),
+                    tag_encoding: tag_encoding.stable(tables),
+                    tag_field: *tag_field,
+                    variants: variants.iter().as_slice().stable(tables),
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
+    type T = TagEncoding;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::TagEncoding::Direct => TagEncoding::Direct,
+            rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
+                TagEncoding::Niche {
+                    untagged_variant: untagged_variant.stable(tables),
+                    niche_variants: niche_variants.stable(tables),
+                    niche_start: *niche_start,
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Abi {
+    type T = ValueAbi;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match *self {
+            rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited,
+            rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)),
+            rustc_abi::Abi::ScalarPair(first, second) => {
+                ValueAbi::ScalarPair(first.stable(tables), second.stable(tables))
+            }
+            rustc_abi::Abi::Vector { element, count } => {
+                ValueAbi::Vector { element: element.stable(tables), count }
+            }
+            rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized },
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Size {
+    type T = Size;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        self.bytes_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Align {
+    type T = Align;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        self.bytes()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
+    type T = Opaque;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        opaque(self)
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
index 7021bdda73501..8b7b26f969c96 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -1,10 +1,10 @@
 //! Conversion of internal Rust compiler items to stable ones.
 
 use rustc_target::abi::FieldIdx;
-use stable_mir::ty::{IndexedVal, VariantIdx};
 
 use crate::rustc_smir::{Stable, Tables};
 
+mod abi;
 mod error;
 mod mir;
 mod ty;
@@ -26,13 +26,6 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
-    type T = VariantIdx;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        VariantIdx::to_val(self.as_usize())
-    }
-}
-
 impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
     type T = stable_mir::mir::CoroutineSource;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -79,14 +72,3 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
         tables.create_span(*self)
     }
 }
-
-impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
-    type T = stable_mir::target::Endian;
-
-    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
-            rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
-        }
-    }
-}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index ae6cf3fe3e86d..cf6ac5285c245 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -12,9 +12,11 @@ use rustc_middle::mir;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use stable_mir::abi::Layout;
 use stable_mir::mir::mono::InstanceDef;
 use stable_mir::ty::{ConstId, Span};
 use stable_mir::ItemKind;
+use std::ops::RangeInclusive;
 use tracing::debug;
 
 use crate::rustc_internal::IndexMap;
@@ -32,6 +34,7 @@ pub struct Tables<'tcx> {
     pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>,
     pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
     pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>,
+    pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>,
 }
 
 impl<'tcx> Tables<'tcx> {
@@ -162,3 +165,13 @@ where
         (self.0.stable(tables), self.1.stable(tables))
     }
 }
+
+impl<'tcx, T> Stable<'tcx> for RangeInclusive<T>
+where
+    T: Stable<'tcx>,
+{
+    type T = RangeInclusive<T::T>;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        RangeInclusive::new(self.start().stable(tables), self.end().stable(tables))
+    }
+}
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
new file mode 100644
index 0000000000000..d4e8e874c1f98
--- /dev/null
+++ b/compiler/stable_mir/src/abi.rs
@@ -0,0 +1,286 @@
+use crate::compiler_interface::with;
+use crate::mir::FieldIdx;
+use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx};
+use crate::Opaque;
+use std::num::NonZeroUsize;
+use std::ops::RangeInclusive;
+
+/// A function ABI definition.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct FnAbi {
+    /// The types of each argument.
+    pub args: Vec<ArgAbi>,
+
+    /// The expected return type.
+    pub ret: ArgAbi,
+
+    /// The count of non-variadic arguments.
+    ///
+    /// Should only be different from `args.len()` when a function is a C variadic function.
+    pub fixed_count: u32,
+
+    /// The ABI convention.
+    pub conv: CallConvention,
+}
+
+impl FnAbi {
+    pub fn is_c_variadic(&self) -> bool {
+        self.args.len() > self.fixed_count as usize
+    }
+}
+
+/// Information about the ABI of a function's argument, or return value.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ArgAbi {
+    pub ty: Ty,
+    pub layout: Layout,
+    pub mode: PassMode,
+}
+
+/// How a function argument should be passed in to the target function.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum PassMode {
+    /// Ignore the argument.
+    ///
+    /// The argument is either uninhabited or a ZST.
+    Ignore,
+    /// Pass the argument directly.
+    ///
+    /// The argument has a layout abi of `Scalar` or `Vector`.
+    Direct,
+    /// Pass a pair's elements directly in two arguments.
+    ///
+    /// The argument has a layout abi of `ScalarPair`.
+    Pair,
+    /// Pass the argument after casting it.
+    Cast,
+    /// Pass the argument indirectly via a hidden pointer.
+    Indirect,
+}
+
+/// The layout of a type, alongside the type itself.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct TyAndLayout {
+    pub ty: Ty,
+    pub layout: Layout,
+}
+
+/// The layout of a type in memory.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct LayoutShape {
+    /// The fields location withing the layout
+    pub fields: FieldsShape,
+
+    /// Encodes information about multi-variant layouts.
+    /// Even with `Multiple` variants, a layout still has its own fields! Those are then
+    /// shared between all variants.
+    ///
+    /// To access all fields of this layout, both `fields` and the fields of the active variant
+    /// must be taken into account.
+    pub variants: VariantsShape,
+
+    /// The `abi` defines how this data is passed between functions.
+    pub abi: ValueAbi,
+
+    /// The ABI mandated alignment in bytes.
+    pub abi_align: Align,
+
+    /// The size of this layout in bytes.
+    pub size: Size,
+}
+
+impl LayoutShape {
+    /// Returns `true` if the layout corresponds to an unsized type.
+    #[inline]
+    pub fn is_unsized(&self) -> bool {
+        self.abi.is_unsized()
+    }
+
+    #[inline]
+    pub fn is_sized(&self) -> bool {
+        !self.abi.is_unsized()
+    }
+
+    /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
+    pub fn is_1zst(&self) -> bool {
+        self.is_sized() && self.size == 0 && self.abi_align == 1
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Layout(usize);
+
+impl Layout {
+    pub fn shape(self) -> LayoutShape {
+        with(|cx| cx.layout_shape(self))
+    }
+}
+
+impl IndexedVal for Layout {
+    fn to_val(index: usize) -> Self {
+        Layout(index)
+    }
+    fn to_index(&self) -> usize {
+        self.0
+    }
+}
+
+/// Describes how the fields of a type are shaped in memory.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum FieldsShape {
+    /// Scalar primitives and `!`, which never have fields.
+    Primitive,
+
+    /// All fields start at no offset. The `usize` is the field count.
+    Union(NonZeroUsize),
+
+    /// Array/vector-like placement, with all fields of identical types.
+    Array { stride: Size, count: u64 },
+
+    /// Struct-like placement, with precomputed offsets.
+    ///
+    /// Fields are guaranteed to not overlap, but note that gaps
+    /// before, between and after all the fields are NOT always
+    /// padding, and as such their contents may not be discarded.
+    /// For example, enum variants leave a gap at the start,
+    /// where the discriminant field in the enum layout goes.
+    Arbitrary {
+        /// Offsets for the first byte of each field,
+        /// ordered to match the source definition order.
+        /// I.e.: It follows the same order as [crate::ty::VariantDef::fields()].
+        /// This vector does not go in increasing order.
+        offsets: Vec<Size>,
+    },
+}
+
+impl FieldsShape {
+    pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
+        match self {
+            FieldsShape::Primitive => vec![],
+            FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(),
+            FieldsShape::Arbitrary { offsets, .. } => {
+                let mut indices = (0..offsets.len()).collect::<Vec<_>>();
+                indices.sort_by_key(|idx| offsets[*idx]);
+                indices
+            }
+        }
+    }
+
+    pub fn count(&self) -> usize {
+        match self {
+            FieldsShape::Primitive => 0,
+            FieldsShape::Union(count) => count.get(),
+            FieldsShape::Array { count, .. } => *count as usize,
+            FieldsShape::Arbitrary { offsets, .. } => offsets.len(),
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum VariantsShape {
+    /// Single enum variants, structs/tuples, unions, and all non-ADTs.
+    Single { index: VariantIdx },
+
+    /// Enum-likes with more than one inhabited variant: each variant comes with
+    /// a *discriminant* (usually the same as the variant index but the user can
+    /// assign explicit discriminant values). That discriminant is encoded
+    /// as a *tag* on the machine. The layout of each variant is
+    /// a struct, and they all have space reserved for the tag.
+    /// For enums, the tag is the sole field of the layout.
+    Multiple {
+        tag: Scalar,
+        tag_encoding: TagEncoding,
+        tag_field: usize,
+        variants: Vec<LayoutShape>,
+    },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum TagEncoding {
+    /// The tag directly stores the discriminant, but possibly with a smaller layout
+    /// (so converting the tag to the discriminant can require sign extension).
+    Direct,
+
+    /// Niche (values invalid for a type) encoding the discriminant:
+    /// Discriminant and variant index coincide.
+    /// The variant `untagged_variant` contains a niche at an arbitrary
+    /// offset (field `tag_field` of the enum), which for a variant with
+    /// discriminant `d` is set to
+    /// `(d - niche_variants.start).wrapping_add(niche_start)`.
+    ///
+    /// For example, `Option<(usize, &T)>`  is represented such that
+    /// `None` has a null pointer for the second tuple field, and
+    /// `Some` is the identity function (with a non-null reference).
+    Niche {
+        untagged_variant: VariantIdx,
+        niche_variants: RangeInclusive<VariantIdx>,
+        niche_start: u128,
+    },
+}
+
+/// Describes how values of the type are passed by target ABIs,
+/// in terms of categories of C types there are ABI rules for.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum ValueAbi {
+    Uninhabited,
+    Scalar(Scalar),
+    ScalarPair(Scalar, Scalar),
+    Vector {
+        element: Scalar,
+        count: u64,
+    },
+    Aggregate {
+        /// If true, the size is exact, otherwise it's only a lower bound.
+        sized: bool,
+    },
+}
+
+impl ValueAbi {
+    /// Returns `true` if the layout corresponds to an unsized type.
+    pub fn is_unsized(&self) -> bool {
+        match *self {
+            ValueAbi::Uninhabited
+            | ValueAbi::Scalar(_)
+            | ValueAbi::ScalarPair(..)
+            | ValueAbi::Vector { .. } => false,
+            ValueAbi::Aggregate { sized } => !sized,
+        }
+    }
+}
+
+/// We currently do not support `Scalar`, and use opaque instead.
+type Scalar = Opaque;
+
+/// General language calling conventions.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum CallConvention {
+    C,
+    Rust,
+
+    Cold,
+    PreserveMost,
+    PreserveAll,
+
+    // Target-specific calling conventions.
+    ArmAapcs,
+    CCmseNonSecureCall,
+
+    Msp430Intr,
+
+    PtxKernel,
+
+    X86Fastcall,
+    X86Intr,
+    X86Stdcall,
+    X86ThisCall,
+    X86VectorCall,
+
+    X86_64SysV,
+    X86_64Win64,
+
+    AmdGpuKernel,
+    AvrInterrupt,
+    AvrNonBlockingInterrupt,
+
+    RiscvInterrupt,
+}
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index 57c60b70d8aa3..98b1d484c034e 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -5,6 +5,7 @@
 
 use std::cell::Cell;
 
+use crate::abi::{FnAbi, Layout, LayoutShape};
 use crate::mir::alloc::{AllocId, GlobalAlloc};
 use crate::mir::mono::{Instance, InstanceDef, StaticDef};
 use crate::mir::Body;
@@ -173,6 +174,15 @@ pub trait Context {
 
     /// Return information about the target machine.
     fn target_info(&self) -> MachineInfo;
+
+    /// Get an instance ABI.
+    fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
+
+    /// Get the layout of a type.
+    fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
+
+    /// Get the layout shape.
+    fn layout_shape(&self, id: Layout) -> LayoutShape;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 8c66bfb2e9890..4941e54fe4b7e 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -33,6 +33,7 @@ use crate::mir::Body;
 use crate::mir::Mutability;
 use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
 
+pub mod abi;
 #[macro_use]
 pub mod crate_def;
 pub mod compiler_interface;
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index c126de23c4b6f..70d44ef8c2256 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,3 +1,4 @@
+use crate::abi::FnAbi;
 use crate::crate_def::CrateDef;
 use crate::mir::Body;
 use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
@@ -56,6 +57,11 @@ impl Instance {
         with(|context| context.instance_ty(self.def))
     }
 
+    /// Retrieve information about this instance binary interface.
+    pub fn fn_abi(&self) -> Result<FnAbi, Error> {
+        with(|cx| cx.instance_abi(self.def))
+    }
+
     /// Retrieve the instance's mangled name used for calling the given instance.
     ///
     /// This will also look up the correct name of instances from upstream crates.
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 4807a9028eb83..1d4d7b6d3520f 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -3,6 +3,7 @@ use super::{
     mir::{Body, Mutability},
     with, DefId, Error, Symbol,
 };
+use crate::abi::Layout;
 use crate::crate_def::CrateDef;
 use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
 use crate::target::MachineInfo;
@@ -85,6 +86,11 @@ impl Ty {
     pub fn unsigned_ty(inner: UintTy) -> Ty {
         Ty::from_rigid_kind(RigidTy::Uint(inner))
     }
+
+    /// Get a type layout.
+    pub fn layout(self) -> Result<Layout, Error> {
+        with(|cx| cx.ty_layout(self))
+    }
 }
 
 impl Ty {
diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs
index 8554630e9c999..7ce3597206b62 100644
--- a/tests/ui-fulldeps/stable-mir/check_allocation.rs
+++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs
@@ -209,7 +209,6 @@ fn check_len(item: CrateItem) {
     assert_eq!(alloc.read_uint(), Ok(2));
 }
 
-// Use internal API to find a function in a crate.
 fn get_item<'a>(
     items: &'a CrateItems,
     item: (ItemKind, &str),
diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs
index ad66751133214..e9a2599d8732c 100644
--- a/tests/ui-fulldeps/stable-mir/check_defs.rs
+++ b/tests/ui-fulldeps/stable-mir/check_defs.rs
@@ -69,9 +69,9 @@ fn extract_elem_ty(ty: Ty) -> Ty {
 
 /// Check signature and type of `Vec::<u8>::new` and its generic version.
 fn test_vec_new(instance: mir::mono::Instance) {
-    let sig = instance.ty().kind().fn_sig().unwrap().skip_binder();
-    assert_matches!(sig.inputs(), &[]);
-    let elem_ty = extract_elem_ty(sig.output());
+    let sig = instance.fn_abi().unwrap();
+    assert_eq!(&sig.args, &[]);
+    let elem_ty = extract_elem_ty(sig.ret.ty);
     assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8)));
 
     // Get the signature for Vec::<T>::new.
diff --git a/tests/ui-fulldeps/stable-mir/check_layout.rs b/tests/ui-fulldeps/stable-mir/check_layout.rs
new file mode 100644
index 0000000000000..1c33103b0feed
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_layout.rs
@@ -0,0 +1,117 @@
+// run-pass
+//! Test information regarding type layout.
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+#![feature(ascii_char, ascii_char_variants)]
+
+extern crate rustc_hir;
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+use rustc_smir::rustc_internal;
+use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
+use stable_mir::mir::mono::Instance;
+use stable_mir::{CrateDef, CrateItems, ItemKind};
+use std::assert_matches::assert_matches;
+use std::convert::TryFrom;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to get information about the test crate.
+fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+    // Find items in the local crate.
+    let items = stable_mir::all_local_items();
+    let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap();
+    let instance = Instance::try_from(target_fn).unwrap();
+    let fn_abi = instance.fn_abi().unwrap();
+    assert_eq!(fn_abi.conv, CallConvention::Rust);
+    assert_eq!(fn_abi.args.len(), 2);
+
+    check_ignore(&fn_abi.args[0]);
+    check_primitive(&fn_abi.args[1]);
+    check_result(fn_abi.ret);
+
+    ControlFlow::Continue(())
+}
+
+/// Check the argument to be ignored: `ignore: [u8; 0]`.
+fn check_ignore(abi: &ArgAbi) {
+    assert!(abi.ty.kind().is_array());
+    assert_eq!(abi.mode, PassMode::Ignore);
+    let layout = abi.layout.shape();
+    assert!(layout.is_sized());
+    assert!(layout.is_1zst());
+}
+
+/// Check the primitive argument: `primitive: char`.
+fn check_primitive(abi: &ArgAbi) {
+    assert!(abi.ty.kind().is_char());
+    assert_eq!(abi.mode, PassMode::Direct);
+    let layout = abi.layout.shape();
+    assert!(layout.is_sized());
+    assert!(!layout.is_1zst());
+    assert_matches!(layout.fields, FieldsShape::Primitive);
+}
+
+/// Check the return value: `Result<usize, &str>`.
+fn check_result(abi: ArgAbi) {
+    assert!(abi.ty.kind().is_enum());
+    assert_eq!(abi.mode, PassMode::Indirect);
+    let layout = abi.layout.shape();
+    assert!(layout.is_sized());
+    assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });
+    assert_matches!(layout.variants, VariantsShape::Multiple { .. })
+}
+
+fn get_item<'a>(
+    items: &'a CrateItems,
+    item: (ItemKind, &str),
+) -> Option<&'a stable_mir::CrateItem> {
+    items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "alloc_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        #[allow(unused_variables)]
+        pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
+            // We only care about the signature.
+            todo!()
+        }}
+        "#
+    )?;
+    Ok(())
+}

From df5b604945276994ad662bd0fd34face0ad609eb Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Tue, 19 Dec 2023 07:40:06 +0100
Subject: [PATCH 3/5] subtype_predicate: remove unnecessary probe

---
 compiler/rustc_infer/src/infer/mod.rs | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3de269da22d65..e092bbbfdd674 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -713,10 +713,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
 }
 
 impl<'tcx, T> InferOk<'tcx, T> {
-    pub fn unit(self) -> InferOk<'tcx, ()> {
-        InferOk { value: (), obligations: self.obligations }
-    }
-
     /// Extracts `value`, registering any obligations into `fulfill_cx`.
     pub fn into_value_registering_obligations(
         self,
@@ -1025,15 +1021,10 @@ impl<'tcx> InferCtxt<'tcx> {
             _ => {}
         }
 
-        Ok(self.commit_if_ok(|_snapshot| {
-            let ty::SubtypePredicate { a_is_expected, a, b } =
-                self.instantiate_binder_with_placeholders(predicate);
-
-            let ok =
-                self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
+        let ty::SubtypePredicate { a_is_expected, a, b } =
+            self.instantiate_binder_with_placeholders(predicate);
 
-            Ok(ok.unit())
-        }))
+        Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
     }
 
     pub fn region_outlives_predicate(

From 90893e4850f463618bd06ae6d3e30f0075559e24 Mon Sep 17 00:00:00 2001
From: Chris Copeland <chris@chrisnc.net>
Date: Sun, 13 Aug 2023 03:51:03 -0700
Subject: [PATCH 4/5] Add arm-none-eabi and armv7r-none-eabi platform-support
 documentation.

---
 src/doc/rustc/src/SUMMARY.md                  |  2 +
 src/doc/rustc/src/platform-support.md         | 42 ++++----
 .../src/platform-support/arm-none-eabi.md     | 96 +++++++++++++++++++
 .../src/platform-support/armv4t-none-eabi.md  | 45 +--------
 .../src/platform-support/armv5te-none-eabi.md | 50 +---------
 .../src/platform-support/armv7r-none-eabi.md  | 47 +++++++++
 6 files changed, 176 insertions(+), 106 deletions(-)
 create mode 100644 src/doc/rustc/src/platform-support/arm-none-eabi.md
 create mode 100644 src/doc/rustc/src/platform-support/armv7r-none-eabi.md

diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index f46daca1f3075..fadd64a0353cb 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -22,8 +22,10 @@
     - [\*-apple-watchos\*](platform-support/apple-watchos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
     - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
+    - [arm-none-eabi](platform-support/arm-none-eabi.md)
     - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
     - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
+    - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 5535e69c86acd..a1d2281ca4884 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -137,17 +137,17 @@ target | std | notes
 [`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android
 `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
 `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
-`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian
-`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat
+[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian
+[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian, hardfloat
 `armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android
 `armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27)
 `armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with MUSL
 `armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with MUSL, hardfloat
-`armv7a-none-eabi` | * | Bare ARMv7-A
-`armv7r-none-eabi` | * | Bare ARMv7-R
-`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
+[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-A
+[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R
+[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, hardfloat
 `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87]
 `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87]
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87]
@@ -166,15 +166,15 @@ target | std | notes
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
 `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
 `sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos
-`thumbv6m-none-eabi` | * | Bare ARMv6-M
-`thumbv7em-none-eabi` | * | Bare ARMv7E-M
-`thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat
-`thumbv7m-none-eabi` | * | Bare ARMv7-M
+[`thumbv6m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv6-M
+[`thumbv7em-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7E-M
+[`thumbv7em-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMV7E-M, hardfloat
+[`thumbv7m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-M
 [`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON
 `thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)
-`thumbv8m.base-none-eabi` | * | Bare ARMv8-M Baseline
-`thumbv8m.main-none-eabi` | * | Bare ARMv8-M Mainline
-`thumbv8m.main-none-eabihf` | * | Bare ARMv8-M Mainline, hardfloat
+[`thumbv8m.base-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Baseline
+[`thumbv8m.main-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline
+[`thumbv8m.main-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline, hardfloat
 `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
 `wasm32-unknown-unknown` | ✓ | WebAssembly
 `wasm32-wasi` | ✓ | WebAssembly with WASI
@@ -238,11 +238,11 @@ target | std | host | notes
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
-[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers
+[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARM Apple WatchOS 64-bit with 32-bit pointers
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
-`armv4t-none-eabi` | * |  | Bare ARMv4T
+[`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Bare ARMv4T
 `armv4t-unknown-linux-gnueabi` | ? |  | ARMv4T Linux
-[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE
+[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Bare ARMv5TE
 `armv5te-unknown-linux-uclibceabi` | ? |  | ARMv5TE Linux with uClibc
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
 [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float
@@ -256,8 +256,8 @@ target | std | host | notes
 `armv7-wrs-vxworks-eabihf` | ? |  | ARMv7-A for VxWorks
 [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
-`armv7a-none-eabihf` | * | | Bare ARMv7-A, hardfloat
-[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS
+[`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare ARMv7-A, hardfloat
+[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARMv7-A Apple WatchOS
 `armv7s-apple-ios` | ✓ |  | ARMv7-A Apple-A6 Apple iOS
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `bpfeb-unknown-none` | * |  | BPF (big endian)
@@ -332,15 +332,15 @@ target | std | host | notes
 [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * |  | Bare 32-bit SPARC V7+
 [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
-`thumbv4t-none-eabi` | * |  | Thumb-mode Bare ARMv4T
-[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE
+[`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Thumb-mode Bare ARMv4T
+[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Thumb-mode Bare ARMv5TE
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7-A Linux with NEON, MUSL
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
-[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS
-[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator
+[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | x86 64-bit tvOS
+[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
 [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | x86 64-bit QNX Neutrino 7.1 RTOS |
 [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `x86_64-pc-windows-msvc` | * |  | 64-bit Windows XP support
diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md
new file mode 100644
index 0000000000000..4f76d0d7bbce7
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md
@@ -0,0 +1,96 @@
+# `{arm,thumb}*-none-eabi(hf)?`
+
+**Tier: 2**
+- [arm(eb)?v7r-none-eabi(hf)?](armv7r-none-eabi.md)
+- armv7a-none-eabi
+- thumbv6m-none-eabi
+- thumbv7m-none-eabi
+- thumbv7em-none-eabi(hf)?
+- thumbv8m.base-none-eabi
+- thumbv8m.main-none-eabi(hf)?
+
+**Tier: 3**
+- [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md)
+- [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md)
+- armv7a-none-eabihf
+
+Bare-metal target for 32-bit ARM CPUs.
+
+If a target has a `*hf` variant, that variant uses the hardware floating-point
+ABI and enables some minimum set of floating-point features based on the FPU(s)
+available in that processor family.
+
+## Requirements
+
+These targets are cross-compiled and use static linking.
+
+By default, the `lld` linker included with Rust will be used; however, you may
+want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux
+from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's
+package manager. To use it, add the following to your `.cargo/config.toml`:
+
+```toml
+[target.<your-target>]
+linker = "arm-none-eabi-ld"
+```
+
+The GNU linker can also be used by specifying `arm-none-eabi-gcc` as the
+linker. This is needed when using GCC's link time optimization.
+
+[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+These targets don't provide a linker script, so you'll need to bring your own
+according to the specific device you are using. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+Targets named `thumb*` instead of `arm*`
+generate Thumb-mode code by default. M-profile processors (`thumbv*m*-*`
+targets) only support Thumb-mode code.
+For the `arm*` targets, Thumb-mode code generation can be enabled by using
+`-C target-feature=+thumb-mode`. Using the unstable
+`#![feature(arm_target_feature)]`, the attribute
+`#[target_feature(enable = "thumb-mode")]` can be applied to individual
+`unsafe` functions to cause those functions to be compiled to Thumb-mode code.
+
+## Building Rust Programs
+
+For the Tier 3 targets in this family, rust does not ship pre-compiled
+artifacts.
+
+Just use the `build-std` nightly cargo feature to build the `core` library. You
+can pass this as a command line argument to cargo, or your `.cargo/config.toml`
+file might include the following lines:
+
+```toml
+[unstable]
+build-std = ["core"]
+```
+
+Most of `core` should work as expected, with the following notes:
+* If the target is not `*hf`, then floating-point operations are emulated in
+  software.
+* Integer division is also emulated in software on some targets, depending on
+  the CPU.
+* Architectures prior to ARMv7 don't have atomic instructions.
+
+`alloc` is also supported, as long as you provide your own global allocator.
+
+Rust programs are output as ELF files.
+
+## Testing
+
+This is a cross-compiled target that you will need to emulate during testing.
+
+The exact emulator that you'll need depends on the specific device you want to
+run your code on.
+
+## Cross-compilation toolchains and C code
+
+The target supports C code compiled with the `arm-none-eabi` target triple and
+a suitable `-march` or `-mcpu` flag.
+
+`gcc` or `clang` can be used, but note that `gcc` uses `-fshort-enums` by
+default for `arm-none*` targets, while `clang` does not. `rustc` matches the
+`gcc` behavior, i.e., the size of a `#[repr(C)] enum` in Rust can be as little
+as 1 byte, rather than 4, as they are on `arm-linux` targets.
diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
index a230eba6bf95c..29c47db8351c7 100644
--- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
@@ -6,51 +6,16 @@ Bare-metal target for any cpu in the ARMv4T architecture family, supporting
 ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
 generation.
 
-In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
-specific with this target, so any ARMv4T device should work fine.
+In particular this supports the Game Boy Advance (GBA), but there's nothing
+GBA-specific with this target, so any ARMv4T device should work fine.
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
 
 ## Target Maintainers
 
 * [@Lokathor](https://github.com/lokathor)
 
-## Requirements
-
-The target is cross-compiled, and uses static linking.
-
-This target doesn't provide a linker script, you'll need to bring your own
-according to the specific device you want to target. Pass
-`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
-`your_script.ld` during linking.
-
-## Building Rust Programs
-
-Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
-
-Just use the `build-std` nightly cargo feature to build the `core` library. You
-can pass this as a command line argument to cargo, or your `.cargo/config.toml`
-file might include the following lines:
-
-```toml
-[unstable]
-build-std = ["core"]
-```
-
-Most of `core` should work as expected, with the following notes:
-* the target is "soft float", so `f32` and `f64` operations are emulated in
-  software.
-* integer division is also emulated in software.
-* the target is old enough that it doesn't have atomic instructions.
-
-Rust programs are output as ELF files.
-
-For running on hardware, you'll generally need to extract the "raw" program code
-out of the ELF and into a file of its own. The `objcopy` program provided as
-part of the GNU Binutils can do this:
-
-```shell
-arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
-```
-
 ## Testing
 
 This is a cross-compiled target that you will need to emulate during testing.
diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
index f469dab1c42fa..37284ba720997 100644
--- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
@@ -8,54 +8,13 @@ generation.
 
 The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `t32`.
 
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
 ## Target Maintainers
 
 * [@QuinnPainter](https://github.com/QuinnPainter)
 
-## Requirements
-
-The target is cross-compiled, and uses static linking.
-
-By default, the `lld` linker included with Rust will be used.
-
-However, you may want to use the `arm-none-eabi-ld` linker instead. This can be obtained for Windows/Mac/Linux from the [ARM
-Developer Website][arm-dev], or possibly from your OS's package manager. To use it, add the following to your `.cargo/config.toml`:
-
-```toml
-[target.armv5te-none-eabi]
-linker = "arm-none-eabi-ld"
-```
-
-[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
-
-This target doesn't provide a linker script, you'll need to bring your own
-according to the specific device you want to target. Pass
-`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
-`your_script.ld` during linking.
-
-## Building Rust Programs
-
-Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
-
-Just use the `build-std` nightly cargo feature to build the `core` library. You
-can pass this as a command line argument to cargo, or your `.cargo/config.toml`
-file might include the following lines:
-
-```toml
-[unstable]
-build-std = ["core"]
-```
-
-Most of `core` should work as expected, with the following notes:
-* the target is "soft float", so `f32` and `f64` operations are emulated in
-  software.
-* integer division is also emulated in software.
-* the target is old enough that it doesn't have atomic instructions.
-
-`alloc` is also supported, as long as you provide your own global allocator.
-
-Rust programs are output as ELF files.
-
 ## Testing
 
 This is a cross-compiled target that you will need to emulate during testing.
@@ -63,4 +22,5 @@ This is a cross-compiled target that you will need to emulate during testing.
 Because this is a device-agnostic target, and the exact emulator that you'll
 need depends on the specific device you want to run your code on.
 
-For example, when programming for the DS, you can use one of the several available DS emulators, such as [melonDS](https://melonds.kuribo64.net/).
+For example, when programming for the DS, you can use one of the several
+available DS emulators, such as [melonDS](https://melonds.kuribo64.net/).
diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
new file mode 100644
index 0000000000000..670cead9e006b
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
@@ -0,0 +1,47 @@
+# `arm(eb)?v7r-none-eabi(hf)?`
+
+**Tier: 2**
+
+Bare-metal target for CPUs in the ARMv7-R architecture family, supporting
+dual ARM/Thumb mode, with ARM mode as the default.
+
+Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
+
+The `eb` versions of this target generate code for big-endian processors.
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
+[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R
+
+## Target maintainers
+
+- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net`
+
+## Requirements
+
+When using the big-endian version of this target, note that some variants of
+the Cortex-R have both big-endian instructions and data. This configuration is
+known as BE-32, while data-only big-endianness is known as BE-8. To build
+programs for BE-32 processors, the GNU linker must be used with the `-mbe32`
+option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness]
+for more details about different endian modes.
+
+When using the hardfloat targets, the minimum floating-point features assumed
+are those of the `vfpv3-d16`, which includes single- and double-precision, with
+16 double-precision registers. This floating-point unit appears in Cortex-R4F
+and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp]
+for more details on the possible FPU variants.
+
+If your processor supports a different set of floating-point features than the
+default expectations of `vfpv3-d16`, then these should also be enabled or
+disabled as needed with `-C target-feature=(+/-)`.
+
+[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness
+
+[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
+
+## Cross-compilation toolchains and C code
+
+This target supports C code compiled with the `arm-none-eabi` target triple and
+`-march=armv7-r` or a suitable `-mcpu` flag.

From 76b3e6de558cc67dca0098def00b0ee55dfc8d58 Mon Sep 17 00:00:00 2001
From: "Celina G. Val" <celinval@amazon.com>
Date: Tue, 19 Dec 2023 11:04:34 -0800
Subject: [PATCH 5/5] Fix c_variadic flag and add opaque info to PassMode

We should expand the information in PassMode later.
---
 .../rustc_smir/src/rustc_smir/convert/abi.rs  | 21 +++++++++---
 compiler/stable_mir/src/abi.rs                | 15 ++++----
 .../{check_layout.rs => check_abi.rs}         | 34 ++++++++++++++++---
 3 files changed, 53 insertions(+), 17 deletions(-)
 rename tests/ui-fulldeps/stable-mir/{check_layout.rs => check_abi.rs} (79%)

diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 46ae0929bcd4a..632e97b32f520 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -66,11 +66,14 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
     type T = FnAbi;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        assert!(self.args.len() >= self.fixed_count as usize);
+        assert!(!self.c_variadic || matches!(self.conv, Conv::C));
         FnAbi {
             args: self.args.as_ref().stable(tables),
             ret: self.ret.stable(tables),
             fixed_count: self.fixed_count,
             conv: self.conv.stable(tables),
+            c_variadic: self.c_variadic,
         }
     }
 }
@@ -122,10 +125,20 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
     fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
         match self {
             rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
-            rustc_target::abi::call::PassMode::Direct(_) => PassMode::Direct,
-            rustc_target::abi::call::PassMode::Pair(_, _) => PassMode::Pair,
-            rustc_target::abi::call::PassMode::Cast { .. } => PassMode::Cast,
-            rustc_target::abi::call::PassMode::Indirect { .. } => PassMode::Indirect,
+            rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
+            rustc_target::abi::call::PassMode::Pair(first, second) => {
+                PassMode::Pair(opaque(first), opaque(second))
+            }
+            rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
+                PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
+            }
+            rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
+                PassMode::Indirect {
+                    attrs: opaque(attrs),
+                    meta_attrs: opaque(meta_attrs),
+                    on_stack: *on_stack,
+                }
+            }
         }
     }
 }
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
index d4e8e874c1f98..53dac6abefb30 100644
--- a/compiler/stable_mir/src/abi.rs
+++ b/compiler/stable_mir/src/abi.rs
@@ -21,12 +21,9 @@ pub struct FnAbi {
 
     /// The ABI convention.
     pub conv: CallConvention,
-}
 
-impl FnAbi {
-    pub fn is_c_variadic(&self) -> bool {
-        self.args.len() > self.fixed_count as usize
-    }
+    /// Whether this is a variadic C function,
+    pub c_variadic: bool,
 }
 
 /// Information about the ABI of a function's argument, or return value.
@@ -47,15 +44,15 @@ pub enum PassMode {
     /// Pass the argument directly.
     ///
     /// The argument has a layout abi of `Scalar` or `Vector`.
-    Direct,
+    Direct(Opaque),
     /// Pass a pair's elements directly in two arguments.
     ///
     /// The argument has a layout abi of `ScalarPair`.
-    Pair,
+    Pair(Opaque, Opaque),
     /// Pass the argument after casting it.
-    Cast,
+    Cast { pad_i32: bool, cast: Opaque },
     /// Pass the argument indirectly via a hidden pointer.
-    Indirect,
+    Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
 }
 
 /// The layout of a type, alongside the type itself.
diff --git a/tests/ui-fulldeps/stable-mir/check_layout.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
similarity index 79%
rename from tests/ui-fulldeps/stable-mir/check_layout.rs
rename to tests/ui-fulldeps/stable-mir/check_abi.rs
index 1c33103b0feed..30b42bc3bfafc 100644
--- a/tests/ui-fulldeps/stable-mir/check_layout.rs
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -23,7 +23,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
 use stable_mir::mir::mono::Instance;
-use stable_mir::{CrateDef, CrateItems, ItemKind};
+use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
 use std::assert_matches::assert_matches;
 use std::convert::TryFrom;
 use std::io::Write;
@@ -35,6 +35,8 @@ const CRATE_NAME: &str = "input";
 fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     // Find items in the local crate.
     let items = stable_mir::all_local_items();
+
+    // Test fn_abi
     let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap();
     let instance = Instance::try_from(target_fn).unwrap();
     let fn_abi = instance.fn_abi().unwrap();
@@ -45,9 +47,26 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     check_primitive(&fn_abi.args[1]);
     check_result(fn_abi.ret);
 
+    // Test variadic function.
+    let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
+    check_variadic(variadic_fn);
+
     ControlFlow::Continue(())
 }
 
+/// Check the variadic function ABI:
+/// ```no_run
+/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {
+///     0
+/// }
+/// ```
+fn check_variadic(variadic_fn: CrateItem) {
+    let instance = Instance::try_from(variadic_fn).unwrap();
+    let abi = instance.fn_abi().unwrap();
+    assert!(abi.c_variadic);
+    assert_eq!(abi.args.len(), 1);
+}
+
 /// Check the argument to be ignored: `ignore: [u8; 0]`.
 fn check_ignore(abi: &ArgAbi) {
     assert!(abi.ty.kind().is_array());
@@ -60,7 +79,7 @@ fn check_ignore(abi: &ArgAbi) {
 /// Check the primitive argument: `primitive: char`.
 fn check_primitive(abi: &ArgAbi) {
     assert!(abi.ty.kind().is_char());
-    assert_eq!(abi.mode, PassMode::Direct);
+    assert_matches!(abi.mode, PassMode::Direct(_));
     let layout = abi.layout.shape();
     assert!(layout.is_sized());
     assert!(!layout.is_1zst());
@@ -70,7 +89,7 @@ fn check_primitive(abi: &ArgAbi) {
 /// Check the return value: `Result<usize, &str>`.
 fn check_result(abi: ArgAbi) {
     assert!(abi.ty.kind().is_enum());
-    assert_eq!(abi.mode, PassMode::Indirect);
+    assert_matches!(abi.mode, PassMode::Indirect { .. });
     let layout = abi.layout.shape();
     assert!(layout.is_sized());
     assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });
@@ -106,11 +125,18 @@ fn generate_input(path: &str) -> std::io::Result<()> {
     write!(
         file,
         r#"
-        #[allow(unused_variables)]
+        #![feature(c_variadic)]
+        #![allow(unused_variables)]
+
         pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
             // We only care about the signature.
             todo!()
         }}
+
+
+        pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
+            0
+        }}
         "#
     )?;
     Ok(())