about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-06-03 21:53:36 +0200
committerGitHub <noreply@github.com>2025-06-03 21:53:36 +0200
commit644f06ec1fd8b17de40d42c699a61020db02a123 (patch)
tree25c8aa492416b29c06ffbf29977bc19622b50204
parentd096ebf8d93e78b429c5c5866ecc60b3a5d9ed18 (diff)
parent307a18dc537fa3f5ee406f0d21c60c26bea18ec8 (diff)
downloadrust-644f06ec1fd8b17de40d42c699a61020db02a123.tar.gz
rust-644f06ec1fd8b17de40d42c699a61020db02a123.zip
Rollup merge of #141569 - workingjubilee:canonicalize-abi, r=bjorn3
Replace ad-hoc ABI "adjustments" with an `AbiMap` to `CanonAbi`

Our `conv_from_spec_abi`, `adjust_abi`, and `is_abi_supported` combine to give us a very confusing way of reasoning about what _actual_ calling convention we want to lower our code to and whether we want to compile the resulting code at all. Instead of leaving this code as a miniature adventure game in which someone tries to combine stateful mutations into a Rube Goldberg machine that will let them escape the maze and arrive at the promised land of codegen, we let `AbiMap` devour this complexity. Once you have an `AbiMap`, you can answer which `ExternAbi`s will lower to what `CanonAbi`s (and whether they will lower at all).

Removed:
- `conv_from_spec_abi` replaced by `AbiMap::canonize_abi`
- `adjust_abi` replaced by same
- `Conv::PreserveAll` as unused
- `Conv::Cold` as unused
- `enum Conv` replaced by `enum CanonAbi`

target-spec.json changes:
- If you have a target-spec.json then now your "entry-abi" key will be specified in terms of one of the `"{abi}"` strings Rust recognizes, e.g.
```json
    "entry-abi": "C",
    "entry-abi": "win64",
    "entry-abi": "aapcs",
```
-rw-r--r--compiler/rustc_abi/src/canon_abi.rs136
-rw-r--r--compiler/rustc_abi/src/extern_abi.rs7
-rw-r--r--compiler/rustc_abi/src/lib.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs49
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs73
-rw-r--r--compiler/rustc_codegen_gcc/src/int.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs69
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs20
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/abi_check.rs8
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs5
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/abi.rs53
-rw-r--r--compiler/rustc_target/src/callconv/arm.rs6
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs109
-rw-r--r--compiler/rustc_target/src/json.rs38
-rw-r--r--compiler/rustc_target/src/spec/abi_map.rs187
-rw-r--r--compiler/rustc_target/src/spec/json.rs30
-rw-r--r--compiler/rustc_target/src/spec/mod.rs122
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs5
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs44
-rw-r--r--src/tools/miri/src/helpers.rs14
-rw-r--r--src/tools/miri/src/shims/aarch64.rs7
-rw-r--r--src/tools/miri/src/shims/backtrace.rs12
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs79
-rw-r--r--src/tools/miri/src/shims/unix/android/foreign_items.rs13
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs6
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs124
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs23
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs38
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/syscall.rs5
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs65
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs33
-rw-r--r--src/tools/miri/src/shims/wasi/foreign_items.rs7
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs12
-rw-r--r--src/tools/miri/src/shims/x86/aesni.rs13
-rw-r--r--src/tools/miri/src/shims/x86/avx.rs41
-rw-r--r--src/tools/miri/src/shims/x86/avx2.rs43
-rw-r--r--src/tools/miri/src/shims/x86/bmi.rs5
-rw-r--r--src/tools/miri/src/shims/x86/gfni.rs9
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs12
-rw-r--r--src/tools/miri/src/shims/x86/sha.rs9
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs21
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs31
-rw-r--r--src/tools/miri/src/shims/x86/sse3.rs7
-rw-r--r--src/tools/miri/src/shims/x86/sse41.rs23
-rw-r--r--src/tools/miri/src/shims/x86/sse42.rs14
-rw-r--r--src/tools/miri/src/shims/x86/ssse3.rs15
-rw-r--r--tests/ui/abi/sysv64-zst.stderr4
48 files changed, 879 insertions, 788 deletions
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs
new file mode 100644
index 00000000000..2cf7648a859
--- /dev/null
+++ b/compiler/rustc_abi/src/canon_abi.rs
@@ -0,0 +1,136 @@
+use std::fmt;
+
+#[cfg(feature = "nightly")]
+use rustc_macros::HashStable_Generic;
+
+use crate::ExternAbi;
+
+/// Calling convention to determine codegen
+///
+/// CanonAbi erases certain distinctions ExternAbi preserves, but remains target-dependent.
+/// There are still both target-specific variants and aliasing variants, though much fewer.
+/// The reason for this step is the frontend may wish to show an ExternAbi but implement that ABI
+/// using a different ABI than the string per se, or describe irrelevant differences, e.g.
+/// - extern "system"
+/// - extern "cdecl"
+/// - extern "C-unwind"
+/// In that sense, this erases mere syntactic distinctions to create a canonical *directive*,
+/// rather than picking the "actual" ABI.
+#[derive(Copy, Clone, Debug)]
+#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+pub enum CanonAbi {
+    // NOTE: the use of nested variants for some ABIs is for many targets they don't matter,
+    // and this pushes the complexity of their reasoning to target-specific code,
+    // allowing a `match` to easily exhaustively ignore these subcategories of variants.
+    // Otherwise it is very tempting to avoid matching exhaustively!
+    C,
+    Rust,
+    RustCold,
+
+    /// ABIs relevant to 32-bit Arm targets
+    Arm(ArmCall),
+    /// ABI relevant to GPUs: the entry point for a GPU kernel
+    GpuKernel,
+
+    /// ABIs relevant to bare-metal interrupt targets
+    // FIXME(workingjubilee): a particular reason for this nesting is we might not need these?
+    // interrupt ABIs should have the same properties:
+    // - uncallable by Rust calls, as LLVM rejects it in most cases
+    // - uses a preserve-all-registers *callee* convention
+    // - should always return `-> !` (effectively... it can't use normal `ret`)
+    // what differs between targets is
+    // - allowed arguments: x86 differs slightly, having 2-3 arguments which are handled magically
+    // - may need special prologues/epilogues for some interrupts, without affecting "call ABI"
+    Interrupt(InterruptKind),
+
+    /// ABIs relevant to Windows or x86 targets
+    X86(X86Call),
+}
+
+impl fmt::Display for CanonAbi {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.to_erased_extern_abi().as_str().fmt(f)
+    }
+}
+
+impl CanonAbi {
+    /// convert to the ExternAbi that *shares a string* with this CanonAbi
+    ///
+    /// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls.
+    /// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values,
+    /// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data.
+    const fn to_erased_extern_abi(self) -> ExternAbi {
+        match self {
+            CanonAbi::C => ExternAbi::C { unwind: false },
+            CanonAbi::Rust => ExternAbi::Rust,
+            CanonAbi::RustCold => ExternAbi::RustCold,
+            CanonAbi::Arm(arm_call) => match arm_call {
+                ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
+                ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
+                ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry,
+            },
+            CanonAbi::GpuKernel => ExternAbi::GpuKernel,
+            CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
+                InterruptKind::Avr => ExternAbi::AvrInterrupt,
+                InterruptKind::AvrNonBlocking => ExternAbi::AvrNonBlockingInterrupt,
+                InterruptKind::Msp430 => ExternAbi::Msp430Interrupt,
+                InterruptKind::RiscvMachine => ExternAbi::RiscvInterruptM,
+                InterruptKind::RiscvSupervisor => ExternAbi::RiscvInterruptS,
+                InterruptKind::X86 => ExternAbi::X86Interrupt,
+            },
+            CanonAbi::X86(x86_call) => match x86_call {
+                X86Call::Fastcall => ExternAbi::Fastcall { unwind: false },
+                X86Call::Stdcall => ExternAbi::Stdcall { unwind: false },
+                X86Call::SysV64 => ExternAbi::SysV64 { unwind: false },
+                X86Call::Thiscall => ExternAbi::Thiscall { unwind: false },
+                X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false },
+                X86Call::Win64 => ExternAbi::Win64 { unwind: false },
+            },
+        }
+    }
+}
+
+/// Callee codegen for interrupts
+///
+/// This is named differently from the "Call" enums because it is different:
+/// these "ABI" differences are not relevant to callers, since there is "no caller".
+/// These only affect callee codegen. making their categorization as distinct ABIs a bit peculiar.
+#[derive(Copy, Clone, Debug)]
+#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+pub enum InterruptKind {
+    Avr,
+    AvrNonBlocking,
+    Msp430,
+    RiscvMachine,
+    RiscvSupervisor,
+    X86,
+}
+
+/// ABIs defined for x86-{32,64}
+///
+/// One of SysV64 or Win64 may alias the C ABI, and arguably Win64 is cross-platform now?
+#[derive(Clone, Copy, Debug)]
+#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+pub enum X86Call {
+    /// "fastcall" has both GNU and Windows variants
+    Fastcall,
+    /// "stdcall" has both GNU and Windows variants
+    Stdcall,
+    SysV64,
+    Thiscall,
+    Vectorcall,
+    Win64,
+}
+
+/// ABIs defined for 32-bit Arm
+#[derive(Copy, Clone, Debug)]
+#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+pub enum ArmCall {
+    Aapcs,
+    CCmseNonSecureCall,
+    CCmseNonSecureEntry,
+}
diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs
index 55f4845d216..c48920e5f1b 100644
--- a/compiler/rustc_abi/src/extern_abi.rs
+++ b/compiler/rustc_abi/src/extern_abi.rs
@@ -7,6 +7,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable};
 
+use crate::AbiFromStrErr;
+
 #[cfg(test)]
 mod tests;
 
@@ -99,11 +101,6 @@ macro_rules! abi_impls {
     }
 }
 
-#[derive(Debug)]
-pub enum AbiFromStrErr {
-    Unknown,
-}
-
 abi_impls! {
     ExternAbi = {
             C { unwind: false } =><= "C",
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 59b74d29221..b806d0aba31 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -55,13 +55,14 @@ use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic};
 
 mod callconv;
+mod canon_abi;
+mod extern_abi;
 mod layout;
 #[cfg(test)]
 mod tests;
 
-mod extern_abi;
-
 pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
+pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
 pub use extern_abi::{ExternAbi, all_names};
 #[cfg(feature = "nightly")]
 pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
@@ -1895,3 +1896,11 @@ pub enum StructKind {
     /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag).
     Prefixed(Size, Align),
 }
+
+#[derive(Clone, Debug)]
+pub enum AbiFromStrErr {
+    /// not a known ABI
+    Unknown,
+    /// no "-unwind" variant can be used here
+    NoExplicitUnwind,
+}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 5f7bf3821d7..fe5b220117f 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -10,7 +10,7 @@ use std::mem;
 use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
 use cranelift_codegen::isa::CallConv;
 use cranelift_module::ModuleError;
-use rustc_abi::ExternAbi;
+use rustc_abi::{CanonAbi, ExternAbi, X86Call};
 use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
-use rustc_target::callconv::{Conv, FnAbi, PassMode};
+use rustc_target::callconv::{FnAbi, PassMode};
 use smallvec::SmallVec;
 
 use self::pass_mode::*;
@@ -42,32 +42,27 @@ fn clif_sig_from_fn_abi<'tcx>(
     Signature { params, returns, call_conv }
 }
 
-pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
+pub(crate) fn conv_to_call_conv(
+    sess: &Session,
+    c: CanonAbi,
+    default_call_conv: CallConv,
+) -> CallConv {
     match c {
-        Conv::Rust | Conv::C => default_call_conv,
-        Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold,
-        Conv::X86_64SysV => CallConv::SystemV,
-        Conv::X86_64Win64 => CallConv::WindowsFastcall,
-
-        // Should already get a back compat warning
-        Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => {
-            default_call_conv
-        }
-
-        Conv::X86Intr | Conv::RiscvInterrupt { .. } => {
-            sess.dcx().fatal(format!("interrupt call conv {c:?} not yet implemented"))
+        CanonAbi::Rust | CanonAbi::C => default_call_conv,
+        CanonAbi::RustCold => CallConv::Cold,
+
+        CanonAbi::X86(x86_call) => match x86_call {
+            X86Call::SysV64 => CallConv::SystemV,
+            X86Call::Win64 => CallConv::WindowsFastcall,
+            // Should already get a back compat warning
+            _ => default_call_conv,
+        },
+
+        CanonAbi::Interrupt(_) | CanonAbi::Arm(_) => {
+            sess.dcx().fatal("call conv {c:?} is not yet implemented")
         }
-
-        Conv::ArmAapcs => sess.dcx().fatal("aapcs call conv not yet implemented"),
-        Conv::CCmseNonSecureCall => {
-            sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented");
-        }
-        Conv::CCmseNonSecureEntry => {
-            sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented");
-        }
-
-        Conv::Msp430Intr | Conv::GpuKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => {
-            unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
+        CanonAbi::GpuKernel => {
+            unreachable!("tried to use {c:?} call conv which only exists on an unsupported target")
         }
     }
 }
@@ -610,7 +605,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         target: CallTarget,
         call_args: &mut Vec<Value>,
     ) {
-        if fn_abi.conv != Conv::C {
+        if fn_abi.conv != CanonAbi::C {
             fx.tcx.dcx().span_fatal(
                 source_info.span,
                 format!("Variadic call for non-C abi {:?}", fn_abi.conv),
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 0c499ba6237..3d0c258f576 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -1,7 +1,7 @@
 #[cfg(feature = "master")]
 use gccjit::FnAttribute;
 use gccjit::{ToLValue, ToRValue, Type};
-use rustc_abi::{Reg, RegKind};
+use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call};
 use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
@@ -10,8 +10,6 @@ use rustc_middle::ty::layout::LayoutOf;
 #[cfg(feature = "master")]
 use rustc_session::config;
 use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode};
-#[cfg(feature = "master")]
-use rustc_target::callconv::{Conv, RiscvInterruptKind};
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
@@ -238,29 +236,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
 }
 
 #[cfg(feature = "master")]
-pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<'gcc>> {
+pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
     let attribute = match conv {
-        Conv::C | Conv::Rust => return None,
-        Conv::CCmseNonSecureCall => {
-            if arch == "arm" {
-                FnAttribute::ArmCmseNonsecureCall
-            } else {
-                return None;
-            }
-        }
-        Conv::CCmseNonSecureEntry => {
-            if arch == "arm" {
-                FnAttribute::ArmCmseNonsecureEntry
-            } else {
-                return None;
-            }
-        }
-        Conv::Cold => FnAttribute::Cold,
-        // NOTE: the preserve attributes are not yet implemented in GCC:
-        // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899
-        Conv::PreserveMost => return None,
-        Conv::PreserveAll => return None,
-        Conv::GpuKernel => {
+        CanonAbi::C | CanonAbi::Rust => return None,
+        CanonAbi::Arm(arm_call) => match arm_call {
+            ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
+            ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
+            ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
+        },
+        CanonAbi::RustCold => FnAttribute::Cold,
+        CanonAbi::GpuKernel => {
             if arch == "amdgpu" {
                 FnAttribute::GcnAmdGpuHsaKernel
             } else if arch == "nvptx64" {
@@ -270,26 +255,24 @@ pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<
             }
         }
         // TODO(antoyo): check if those AVR attributes are mapped correctly.
-        Conv::AvrInterrupt => FnAttribute::AvrSignal,
-        Conv::AvrNonBlockingInterrupt => FnAttribute::AvrInterrupt,
-        Conv::ArmAapcs => FnAttribute::ArmPcs("aapcs"),
-        Conv::Msp430Intr => FnAttribute::Msp430Interrupt,
-        Conv::RiscvInterrupt { kind } => {
-            let kind = match kind {
-                RiscvInterruptKind::Machine => "machine",
-                RiscvInterruptKind::Supervisor => "supervisor",
-            };
-            FnAttribute::RiscvInterrupt(kind)
-        }
-        Conv::X86Fastcall => FnAttribute::X86FastCall,
-        Conv::X86Intr => FnAttribute::X86Interrupt,
-        Conv::X86Stdcall => FnAttribute::X86Stdcall,
-        Conv::X86ThisCall => FnAttribute::X86ThisCall,
-        // NOTE: the vectorcall calling convention is not yet implemented in GCC:
-        // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
-        Conv::X86VectorCall => return None,
-        Conv::X86_64SysV => FnAttribute::X86SysvAbi,
-        Conv::X86_64Win64 => FnAttribute::X86MsAbi,
+        CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
+            InterruptKind::Avr => FnAttribute::AvrSignal,
+            InterruptKind::AvrNonBlocking => FnAttribute::AvrInterrupt,
+            InterruptKind::Msp430 => FnAttribute::Msp430Interrupt,
+            InterruptKind::RiscvMachine => FnAttribute::RiscvInterrupt("machine"),
+            InterruptKind::RiscvSupervisor => FnAttribute::RiscvInterrupt("supervisor"),
+            InterruptKind::X86 => FnAttribute::X86Interrupt,
+        },
+        CanonAbi::X86(x86_call) => match x86_call {
+            X86Call::Fastcall => FnAttribute::X86FastCall,
+            X86Call::Stdcall => FnAttribute::X86Stdcall,
+            X86Call::Thiscall => FnAttribute::X86ThisCall,
+            // // NOTE: the vectorcall calling convention is not yet implemented in GCC:
+            // // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+            X86Call::Vectorcall => return None,
+            X86Call::SysV64 => FnAttribute::X86SysvAbi,
+            X86Call::Win64 => FnAttribute::X86MsAbi,
+        },
     };
     Some(attribute)
 }
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index 9b5b0fde6e2..eb4acd8ade9 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -3,11 +3,11 @@
 //! 128-bit integers on 32-bit platforms and thus require to be handled manually.
 
 use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
-use rustc_abi::{Endian, ExternAbi};
+use rustc_abi::{CanonAbi, Endian, ExternAbi};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::callconv::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
+use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode};
 
 use crate::builder::{Builder, ToGccComp};
 use crate::common::{SignType, TypeReflection};
@@ -397,7 +397,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             ret: arg_abi,
             c_variadic: false,
             fixed_count: 3,
-            conv: Conv::C,
+            conv: CanonAbi::C,
             can_unwind: false,
         };
         fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false });
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index c87e70864e5..119cd634f98 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -2,7 +2,10 @@ use std::borrow::Borrow;
 use std::cmp;
 
 use libc::c_uint;
-use rustc_abi::{BackendRepr, HasDataLayout, Primitive, Reg, RegKind, Size};
+use rustc_abi::{
+    ArmCall, BackendRepr, CanonAbi, HasDataLayout, InterruptKind, Primitive, Reg, RegKind, Size,
+    X86Call,
+};
 use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
@@ -12,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::{bug, ty};
 use rustc_session::config;
 use rustc_target::callconv::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, Conv, FnAbi, PassMode,
+    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode,
 };
 use rustc_target::spec::SanitizerSet;
 use smallvec::SmallVec;
@@ -409,11 +412,17 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         if !self.can_unwind {
             func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx));
         }
-        if let Conv::RiscvInterrupt { kind } = self.conv {
-            func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str()));
-        }
-        if let Conv::CCmseNonSecureEntry = self.conv {
-            func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"))
+        match self.conv {
+            CanonAbi::Interrupt(InterruptKind::RiscvMachine) => {
+                func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "machine"))
+            }
+            CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) => {
+                func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "supervisor"))
+            }
+            CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) => {
+                func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"))
+            }
+            _ => (),
         }
         attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs });
 
@@ -600,7 +609,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             llvm::SetInstructionCallConv(callsite, cconv);
         }
 
-        if self.conv == Conv::CCmseNonSecureCall {
+        if self.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) {
             // This will probably get ignored on all targets but those supporting the TrustZone-M
             // extension (thumbv8m targets).
             let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call");
@@ -636,17 +645,11 @@ impl AbiBuilderMethods for Builder<'_, '_, '_> {
 }
 
 impl llvm::CallConv {
-    pub(crate) fn from_conv(conv: Conv, arch: &str) -> Self {
+    pub(crate) fn from_conv(conv: CanonAbi, arch: &str) -> Self {
         match conv {
-            Conv::C
-            | Conv::Rust
-            | Conv::CCmseNonSecureCall
-            | Conv::CCmseNonSecureEntry
-            | Conv::RiscvInterrupt { .. } => llvm::CCallConv,
-            Conv::Cold => llvm::ColdCallConv,
-            Conv::PreserveMost => llvm::PreserveMost,
-            Conv::PreserveAll => llvm::PreserveAll,
-            Conv::GpuKernel => {
+            CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
+            CanonAbi::RustCold => llvm::PreserveMost,
+            CanonAbi::GpuKernel => {
                 if arch == "amdgpu" {
                     llvm::AmdgpuKernel
                 } else if arch == "nvptx64" {
@@ -655,17 +658,25 @@ impl llvm::CallConv {
                     panic!("Architecture {arch} does not support GpuKernel calling convention");
                 }
             }
-            Conv::AvrInterrupt => llvm::AvrInterrupt,
-            Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
-            Conv::ArmAapcs => llvm::ArmAapcsCallConv,
-            Conv::Msp430Intr => llvm::Msp430Intr,
-            Conv::X86Fastcall => llvm::X86FastcallCallConv,
-            Conv::X86Intr => llvm::X86_Intr,
-            Conv::X86Stdcall => llvm::X86StdcallCallConv,
-            Conv::X86ThisCall => llvm::X86_ThisCall,
-            Conv::X86VectorCall => llvm::X86_VectorCall,
-            Conv::X86_64SysV => llvm::X86_64_SysV,
-            Conv::X86_64Win64 => llvm::X86_64_Win64,
+            CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
+                InterruptKind::Avr => llvm::AvrInterrupt,
+                InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt,
+                InterruptKind::Msp430 => llvm::Msp430Intr,
+                InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv,
+                InterruptKind::X86 => llvm::X86_Intr,
+            },
+            CanonAbi::Arm(arm_call) => match arm_call {
+                ArmCall::Aapcs => llvm::ArmAapcsCallConv,
+                ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv,
+            },
+            CanonAbi::X86(x86_call) => match x86_call {
+                X86Call::Fastcall => llvm::X86FastcallCallConv,
+                X86Call::Stdcall => llvm::X86StdcallCallConv,
+                X86Call::SysV64 => llvm::X86_64_SysV,
+                X86Call::Thiscall => llvm::X86_ThisCall,
+                X86Call::Vectorcall => llvm::X86_VectorCall,
+                X86Call::Win64 => llvm::X86_64_Win64,
+            },
         }
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index e26f999773d..92b9b6e132e 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -1,5 +1,6 @@
 use std::collections::hash_map::Entry::*;
 
+use rustc_abi::{CanonAbi, X86Call};
 use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name};
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def::DefKind;
@@ -14,7 +15,6 @@ use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolNam
 use rustc_middle::util::Providers;
 use rustc_session::config::{CrateType, OomStrategy};
 use rustc_symbol_mangling::mangle_internal_symbol;
-use rustc_target::callconv::Conv;
 use rustc_target::spec::{SanitizerSet, TlsModel};
 use tracing::debug;
 
@@ -652,7 +652,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>(
 fn calling_convention_for_symbol<'tcx>(
     tcx: TyCtxt<'tcx>,
     symbol: ExportedSymbol<'tcx>,
-) -> (Conv, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) {
+) -> (CanonAbi, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) {
     let instance = match symbol {
         ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _)
             if tcx.is_static(def_id) =>
@@ -683,7 +683,7 @@ fn calling_convention_for_symbol<'tcx>(
         })
         .map(|fnabi| (fnabi.conv, &fnabi.args[..]))
         // FIXME(workingjubilee): why don't we know the convention here?
-        .unwrap_or((Conv::Rust, &[]))
+        .unwrap_or((CanonAbi::Rust, &[]))
 }
 
 /// This is the symbol name of the given instance as seen by the linker.
@@ -717,14 +717,14 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
         _ => return undecorated,
     };
 
-    let (conv, args) = calling_convention_for_symbol(tcx, symbol);
+    let (callconv, args) = calling_convention_for_symbol(tcx, symbol);
 
     // Decorate symbols with prefixes, suffixes and total number of bytes of arguments.
     // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170
-    let (prefix, suffix) = match conv {
-        Conv::X86Fastcall => ("@", "@"),
-        Conv::X86Stdcall => ("_", "@"),
-        Conv::X86VectorCall => ("", "@@"),
+    let (prefix, suffix) = match callconv {
+        CanonAbi::X86(X86Call::Fastcall) => ("@", "@"),
+        CanonAbi::X86(X86Call::Stdcall) => ("_", "@"),
+        CanonAbi::X86(X86Call::Vectorcall) => ("", "@@"),
         _ => {
             if let Some(prefix) = prefix {
                 undecorated.insert(0, prefix);
@@ -758,9 +758,9 @@ pub(crate) fn extend_exported_symbols<'tcx>(
     symbol: ExportedSymbol<'tcx>,
     instantiating_crate: CrateNum,
 ) {
-    let (conv, _) = calling_convention_for_symbol(tcx, symbol);
+    let (callconv, _) = calling_convention_for_symbol(tcx, symbol);
 
-    if conv != Conv::GpuKernel || tcx.sess.target.os != "amdhsa" {
+    if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != "amdhsa" {
         return;
     }
 
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 7d4afc9d3d9..51bdd04267c 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -118,7 +118,7 @@ const_eval_frame_note_inner = inside {$where_ ->
 const_eval_frame_note_last = the failure occurred here
 
 const_eval_incompatible_calling_conventions =
-    calling a function with calling convention {$callee_conv} using calling convention {$caller_conv}
+    calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}"
 
 const_eval_incompatible_return_types =
     calling a function with return type {$callee_ty} passing return place of type {$caller_ty}
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index cfeaee07776..5478e54a606 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -1,6 +1,6 @@
 //! This module ensures that if a function's ABI requires a particular target feature,
 //! that target feature is enabled both on the callee and all callers.
-use rustc_abi::{BackendRepr, RegKind};
+use rustc_abi::{BackendRepr, CanonAbi, RegKind, X86Call};
 use rustc_hir::{CRATE_HIR_ID, HirId};
 use rustc_middle::mir::{self, Location, traversal};
 use rustc_middle::ty::layout::LayoutCx;
@@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv};
 use rustc_session::lint::builtin::WASM_C_ABI;
 use rustc_span::def_id::DefId;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
-use rustc_target::callconv::{ArgAbi, Conv, FnAbi, PassMode};
+use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
 use rustc_target::spec::{HasWasmCAbiOpt, WasmCAbi};
 
 use crate::errors;
@@ -72,7 +72,7 @@ fn do_check_simd_vector_abi<'tcx>(
         }
     }
     // The `vectorcall` ABI is special in that it requires SSE2 no matter which types are being passed.
-    if abi.conv == Conv::X86VectorCall && !have_feature(sym::sse2) {
+    if abi.conv == CanonAbi::X86(X86Call::Vectorcall) && !have_feature(sym::sse2) {
         let (span, _hir_id) = loc();
         tcx.dcx().emit_err(errors::AbiRequiredTargetFeature {
             span,
@@ -128,7 +128,7 @@ fn do_check_wasm_abi<'tcx>(
     if !(tcx.sess.target.arch == "wasm32"
         && tcx.sess.target.os == "unknown"
         && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true }
-        && abi.conv == Conv::C)
+        && abi.conv == CanonAbi::C)
     {
         return;
     }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
index 562e288afaa..82e18ad497b 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
@@ -4,10 +4,11 @@
 //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
 //! see design document in the tracking issue #89653.
 
+use rustc_abi::CanonAbi;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_target::callconv::{Conv, FnAbi, PassMode};
+use rustc_target::callconv::{FnAbi, PassMode};
 use tracing::instrument;
 
 mod encode;
@@ -45,7 +46,7 @@ pub fn typeid_for_fnabi<'tcx>(
     let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
     match fn_abi.conv {
-        Conv::C => {
+        CanonAbi::C => {
             encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
         }
         _ => {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 7ccc785a400..06dfaf079a3 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -2,8 +2,9 @@
 
 #![allow(rustc::usage_of_qualified_ty)]
 
+use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
 use rustc_middle::ty;
-use rustc_target::callconv::{self, Conv};
+use rustc_target::callconv;
 use stable_mir::abi::{
     AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
     LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
@@ -69,7 +70,7 @@ impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> {
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         assert!(self.args.len() >= self.fixed_count as usize);
-        assert!(!self.c_variadic || matches!(self.conv, Conv::C));
+        assert!(!self.c_variadic || matches!(self.conv, CanonAbi::C));
         FnAbi {
             args: self.args.as_ref().stable(tables),
             ret: self.ret.stable(tables),
@@ -92,31 +93,37 @@ impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> {
     }
 }
 
-impl<'tcx> Stable<'tcx> for callconv::Conv {
+impl<'tcx> Stable<'tcx> for CanonAbi {
     type T = CallConvention;
 
     fn stable(&self, _tables: &mut Tables<'_>) -> 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::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry,
-            Conv::Msp430Intr => CallConvention::Msp430Intr,
-            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::GpuKernel => CallConvention::GpuKernel,
-            Conv::AvrInterrupt => CallConvention::AvrInterrupt,
-            Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt,
-            Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt,
+            CanonAbi::C => CallConvention::C,
+            CanonAbi::Rust => CallConvention::Rust,
+            CanonAbi::RustCold => CallConvention::Cold,
+            CanonAbi::Arm(arm_call) => match arm_call {
+                ArmCall::Aapcs => CallConvention::ArmAapcs,
+                ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
+                ArmCall::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry,
+            },
+            CanonAbi::GpuKernel => CallConvention::GpuKernel,
+            CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
+                InterruptKind::Avr => CallConvention::AvrInterrupt,
+                InterruptKind::AvrNonBlocking => CallConvention::AvrNonBlockingInterrupt,
+                InterruptKind::Msp430 => CallConvention::Msp430Intr,
+                InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => {
+                    CallConvention::RiscvInterrupt
+                }
+                InterruptKind::X86 => CallConvention::X86Intr,
+            },
+            CanonAbi::X86(x86_call) => match x86_call {
+                X86Call::Fastcall => CallConvention::X86Fastcall,
+                X86Call::Stdcall => CallConvention::X86Stdcall,
+                X86Call::SysV64 => CallConvention::X86_64SysV,
+                X86Call::Thiscall => CallConvention::X86ThisCall,
+                X86Call::Vectorcall => CallConvention::X86VectorCall,
+                X86Call::Win64 => CallConvention::X86_64Win64,
+            },
         }
     }
 }
diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs
index 0a5dcc66347..70830fa07b6 100644
--- a/compiler/rustc_target/src/callconv/arm.rs
+++ b/compiler/rustc_target/src/callconv/arm.rs
@@ -1,6 +1,6 @@
-use rustc_abi::{HasDataLayout, TyAbiInterface};
+use rustc_abi::{ArmCall, CanonAbi, HasDataLayout, TyAbiInterface};
 
-use crate::callconv::{ArgAbi, Conv, FnAbi, Reg, RegKind, Uniform};
+use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
 use crate::spec::HasTargetSpec;
 
 fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
@@ -90,7 +90,7 @@ where
     // If this is a target with a hard-float ABI, and the function is not explicitly
     // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates.
     let vfp = cx.target_spec().llvm_target.ends_with("hf")
-        && fn_abi.conv != Conv::ArmAapcs
+        && fn_abi.conv != CanonAbi::Arm(ArmCall::Aapcs)
         && !fn_abi.c_variadic;
 
     if !fn_abi.ret.is_ignore() {
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 907614520a2..d2e49cea647 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -1,13 +1,12 @@
-use std::fmt::Display;
-use std::str::FromStr;
 use std::{fmt, iter};
 
 use rustc_abi::{
-    AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, Scalar,
-    Size, TyAbiInterface, TyAndLayout,
+    AddressSpace, Align, BackendRepr, CanonAbi, ExternAbi, HasDataLayout, Primitive, Reg, RegKind,
+    Scalar, Size, TyAbiInterface, TyAndLayout,
 };
 use rustc_macros::HashStable_Generic;
 
+pub use crate::spec::AbiMap;
 use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi};
 
 mod aarch64;
@@ -530,41 +529,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum Conv {
-    // General language calling conventions, for which every target
-    // should have its own backend (e.g. LLVM) support.
-    C,
-    Rust,
-
-    Cold,
-    PreserveMost,
-    PreserveAll,
-
-    // Target-specific calling conventions.
-    ArmAapcs,
-    CCmseNonSecureCall,
-    CCmseNonSecureEntry,
-
-    Msp430Intr,
-
-    GpuKernel,
-
-    X86Fastcall,
-    X86Intr,
-    X86Stdcall,
-    X86ThisCall,
-    X86VectorCall,
-
-    X86_64SysV,
-    X86_64Win64,
-
-    AvrInterrupt,
-    AvrNonBlockingInterrupt,
-
-    RiscvInterrupt { kind: RiscvInterruptKind },
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum RiscvInterruptKind {
     Machine,
     Supervisor,
@@ -605,7 +569,7 @@ pub struct FnAbi<'a, Ty> {
     /// This can be used to know whether an argument is variadic or not.
     pub fixed_count: u32,
     /// The calling convention of this function.
-    pub conv: Conv,
+    pub conv: CanonAbi,
     /// Indicates if an unwind may happen across a call to this function.
     pub can_unwind: bool,
 }
@@ -696,7 +660,6 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
             "nvptx64" => {
-                let abi = cx.target_spec().adjust_abi(abi, self.c_variadic);
                 if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel {
                     nvptx64::compute_ptx_kernel_abi_info(cx, self)
                 } else {
@@ -863,70 +826,6 @@ impl<'a, Ty> FnAbi<'a, Ty> {
     }
 }
 
-impl FromStr for Conv {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "C" => Ok(Conv::C),
-            "Rust" => Ok(Conv::Rust),
-            "RustCold" => Ok(Conv::Rust),
-            "ArmAapcs" => Ok(Conv::ArmAapcs),
-            "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall),
-            "CCmseNonSecureEntry" => Ok(Conv::CCmseNonSecureEntry),
-            "Msp430Intr" => Ok(Conv::Msp430Intr),
-            "X86Fastcall" => Ok(Conv::X86Fastcall),
-            "X86Intr" => Ok(Conv::X86Intr),
-            "X86Stdcall" => Ok(Conv::X86Stdcall),
-            "X86ThisCall" => Ok(Conv::X86ThisCall),
-            "X86VectorCall" => Ok(Conv::X86VectorCall),
-            "X86_64SysV" => Ok(Conv::X86_64SysV),
-            "X86_64Win64" => Ok(Conv::X86_64Win64),
-            "GpuKernel" => Ok(Conv::GpuKernel),
-            "AvrInterrupt" => Ok(Conv::AvrInterrupt),
-            "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
-            "RiscvInterrupt(machine)" => {
-                Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine })
-            }
-            "RiscvInterrupt(supervisor)" => {
-                Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor })
-            }
-            _ => Err(format!("'{s}' is not a valid value for entry function call convention.")),
-        }
-    }
-}
-
-fn conv_to_externabi(conv: &Conv) -> ExternAbi {
-    match conv {
-        Conv::C => ExternAbi::C { unwind: false },
-        Conv::Rust => ExternAbi::Rust,
-        Conv::PreserveMost => ExternAbi::RustCold,
-        Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false },
-        Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
-        Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry,
-        Conv::Msp430Intr => ExternAbi::Msp430Interrupt,
-        Conv::GpuKernel => ExternAbi::GpuKernel,
-        Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false },
-        Conv::X86Intr => ExternAbi::X86Interrupt,
-        Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false },
-        Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false },
-        Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false },
-        Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false },
-        Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false },
-        Conv::AvrInterrupt => ExternAbi::AvrInterrupt,
-        Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt,
-        Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM,
-        Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS,
-        Conv::Cold | Conv::PreserveAll => unreachable!(),
-    }
-}
-
-impl Display for Conv {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", conv_to_externabi(self))
-    }
-}
-
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs
index 8d6f8f4c6f6..4fcc477921b 100644
--- a/compiler/rustc_target/src/json.rs
+++ b/compiler/rustc_target/src/json.rs
@@ -92,38 +92,6 @@ impl<A: ToJson> ToJson for Option<A> {
     }
 }
 
-impl ToJson for crate::callconv::Conv {
-    fn to_json(&self) -> Json {
-        let buf: String;
-        let s = match self {
-            Self::C => "C",
-            Self::Rust => "Rust",
-            Self::Cold => "Cold",
-            Self::PreserveMost => "PreserveMost",
-            Self::PreserveAll => "PreserveAll",
-            Self::ArmAapcs => "ArmAapcs",
-            Self::CCmseNonSecureCall => "CCmseNonSecureCall",
-            Self::CCmseNonSecureEntry => "CCmseNonSecureEntry",
-            Self::Msp430Intr => "Msp430Intr",
-            Self::X86Fastcall => "X86Fastcall",
-            Self::X86Intr => "X86Intr",
-            Self::X86Stdcall => "X86Stdcall",
-            Self::X86ThisCall => "X86ThisCall",
-            Self::X86VectorCall => "X86VectorCall",
-            Self::X86_64SysV => "X86_64SysV",
-            Self::X86_64Win64 => "X86_64Win64",
-            Self::GpuKernel => "GpuKernel",
-            Self::AvrInterrupt => "AvrInterrupt",
-            Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt",
-            Self::RiscvInterrupt { kind } => {
-                buf = format!("RiscvInterrupt({})", kind.as_str());
-                &buf
-            }
-        };
-        Json::String(s.to_owned())
-    }
-}
-
 impl ToJson for TargetMetadata {
     fn to_json(&self) -> Json {
         json!({
@@ -140,3 +108,9 @@ impl ToJson for rustc_abi::Endian {
         self.as_str().to_json()
     }
 }
+
+impl ToJson for rustc_abi::CanonAbi {
+    fn to_json(&self) -> Json {
+        self.to_string().to_json()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs
new file mode 100644
index 00000000000..d9101f79f04
--- /dev/null
+++ b/compiler/rustc_target/src/spec/abi_map.rs
@@ -0,0 +1,187 @@
+use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
+
+use crate::spec::Target;
+
+/// Mapping for ExternAbi to CanonAbi according to a Target
+///
+/// A maybe-transitional structure circa 2025 for hosting future experiments in
+/// encapsulating arch-specific ABI lowering details to make them more testable.
+#[derive(Clone, Debug)]
+pub struct AbiMap {
+    arch: Arch,
+    os: OsKind,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum AbiMapping {
+    /// this ABI is exactly mapped for this platform
+    Direct(CanonAbi),
+    /// we don't yet warn on this, but we will
+    Deprecated(CanonAbi),
+    Invalid,
+}
+
+impl AbiMapping {
+    pub fn into_option(self) -> Option<CanonAbi> {
+        match self {
+            Self::Direct(abi) | Self::Deprecated(abi) => Some(abi),
+            Self::Invalid => None,
+        }
+    }
+
+    pub fn unwrap(self) -> CanonAbi {
+        self.into_option().unwrap()
+    }
+
+    pub fn is_mapped(self) -> bool {
+        self.into_option().is_some()
+    }
+}
+
+impl AbiMap {
+    pub fn from_target(target: &Target) -> Self {
+        // the purpose of this little exercise is to force listing what affects these mappings
+        let arch = match &*target.arch {
+            "aarch64" => Arch::Aarch64,
+            "amdgpu" => Arch::Amdgpu,
+            "arm" if target.llvm_target.starts_with("thumbv8m") => Arch::Arm(ArmVer::ThumbV8M),
+            "arm" => Arch::Arm(ArmVer::Other),
+            "avr" => Arch::Avr,
+            "msp430" => Arch::Msp430,
+            "nvptx64" => Arch::Nvptx,
+            "riscv32" | "riscv64" => Arch::Riscv,
+            "x86" => Arch::X86,
+            "x86_64" => Arch::X86_64,
+            _ => Arch::Other,
+        };
+        let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other };
+        AbiMap { arch, os }
+    }
+
+    pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
+        let AbiMap { os, arch } = *self;
+
+        let canon_abi = match (extern_abi, arch) {
+            // infallible lowerings
+            (ExternAbi::C { .. }, _) => CanonAbi::C,
+            (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
+            (ExternAbi::Unadjusted, _) => CanonAbi::C,
+
+            (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
+            (ExternAbi::RustCold, _) => CanonAbi::RustCold,
+
+            (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
+                CanonAbi::X86(X86Call::Stdcall)
+            }
+            (ExternAbi::System { .. }, _) => CanonAbi::C,
+
+            // fallible lowerings
+            (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
+            (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
+            (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C,
+            (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
+            (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => {
+                CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
+            }
+            (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => {
+                CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
+            }
+            (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => {
+                return AbiMapping::Invalid;
+            }
+
+            (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C,
+            (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
+
+            (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall),
+            (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
+                return AbiMapping::Deprecated(CanonAbi::C);
+            }
+            (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall),
+            (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
+                return AbiMapping::Deprecated(CanonAbi::C);
+            }
+            (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall),
+            (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => {
+                CanonAbi::X86(X86Call::Vectorcall)
+            }
+            (ExternAbi::Vectorcall { .. }, _) if os == OsKind::Windows => {
+                return AbiMapping::Deprecated(CanonAbi::C);
+            }
+            (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64),
+            (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64),
+            (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel,
+            (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel,
+            (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
+
+            (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
+            (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => {
+                CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
+            }
+            (ExternAbi::Msp430Interrupt, Arch::Msp430) => {
+                CanonAbi::Interrupt(InterruptKind::Msp430)
+            }
+            (ExternAbi::RiscvInterruptM, Arch::Riscv) => {
+                CanonAbi::Interrupt(InterruptKind::RiscvMachine)
+            }
+            (ExternAbi::RiscvInterruptS, Arch::Riscv) => {
+                CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
+            }
+            (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => {
+                CanonAbi::Interrupt(InterruptKind::X86)
+            }
+            (
+                ExternAbi::AvrInterrupt
+                | ExternAbi::AvrNonBlockingInterrupt
+                | ExternAbi::Msp430Interrupt
+                | ExternAbi::RiscvInterruptM
+                | ExternAbi::RiscvInterruptS
+                | ExternAbi::X86Interrupt,
+                _,
+            ) => return AbiMapping::Invalid,
+        };
+
+        AbiMapping::Direct(canon_abi)
+    }
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+enum Arch {
+    Aarch64,
+    Amdgpu,
+    Arm(ArmVer),
+    Avr,
+    Msp430,
+    Nvptx,
+    Riscv,
+    X86,
+    X86_64,
+    /// Architectures which don't need other considerations for ABI lowering
+    Other,
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+enum OsKind {
+    Windows,
+    Other,
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+enum ArmVer {
+    ThumbV8M,
+    Other,
+}
diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs
index be71da76b4a..54b06d9f9b4 100644
--- a/compiler/rustc_target/src/spec/json.rs
+++ b/compiler/rustc_target/src/spec/json.rs
@@ -2,10 +2,12 @@ use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::str::FromStr;
 
+use rustc_abi::ExternAbi;
 use serde_json::Value;
 
 use super::{Target, TargetKind, TargetOptions, TargetWarnings};
 use crate::json::{Json, ToJson};
+use crate::spec::AbiMap;
 
 impl Target {
     /// Loads a target descriptor from a JSON object.
@@ -515,18 +517,6 @@ impl Target {
                     }
                 }
             } );
-            ($key_name:ident, Conv) => ( {
-                let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
-                    match super::Conv::from_str(s) {
-                        Ok(c) => {
-                            base.$key_name = c;
-                            Some(Ok(()))
-                        }
-                        Err(e) => Some(Err(e))
-                    }
-                })).unwrap_or(Ok(()))
-            } );
         }
 
         if let Some(j) = obj.remove("target-endian") {
@@ -660,9 +650,23 @@ impl Target {
         key!(supports_stack_protector, bool);
         key!(small_data_threshold_support, SmallDataThresholdSupport)?;
         key!(entry_name);
-        key!(entry_abi, Conv)?;
         key!(supports_xray, bool);
 
+        // we're going to run `update_from_cli`, but that won't change the target's AbiMap
+        // FIXME: better factor the Target definition so we enforce this on a type level
+        let abi_map = AbiMap::from_target(&base);
+
+        if let Some(abi_str) = obj.remove("entry-abi") {
+            if let Json::String(abi_str) = abi_str {
+                match abi_str.parse::<ExternAbi>() {
+                    Ok(abi) => base.options.entry_abi = abi_map.canonize_abi(abi, false).unwrap(),
+                    Err(_) => return Err(format!("{abi_str} is not a valid ExternAbi")),
+                }
+            } else {
+                incorrect_type.push("entry-abi".to_owned())
+            }
+        }
+
         base.update_from_cli();
         base.check_consistency(TargetKind::Json)?;
 
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 303be54a6d7..6529c2d72c8 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -43,7 +43,7 @@ use std::str::FromStr;
 use std::{fmt, io};
 
 use rustc_abi::{
-    Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
+    Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
 };
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_fs_util::try_canonicalize;
@@ -53,15 +53,16 @@ use rustc_span::{Symbol, kw, sym};
 use serde_json::Value;
 use tracing::debug;
 
-use crate::callconv::Conv;
 use crate::json::{Json, ToJson};
 use crate::spec::crt_objects::CrtObjects;
 
 pub mod crt_objects;
 
+mod abi_map;
 mod base;
 mod json;
 
+pub use abi_map::AbiMap;
 pub use base::apple;
 pub use base::avr::ef_avr_arch;
 
@@ -2655,9 +2656,9 @@ pub struct TargetOptions {
     /// Default value is "main"
     pub entry_name: StaticCow<str>,
 
-    /// The ABI of entry function.
-    /// Default value is `Conv::C`, i.e. C call convention
-    pub entry_abi: Conv,
+    /// The ABI of the entry function.
+    /// Default value is `CanonAbi::C`
+    pub entry_abi: CanonAbi,
 
     /// Whether the target supports XRay instrumentation.
     pub supports_xray: bool,
@@ -2888,7 +2889,7 @@ impl Default for TargetOptions {
             generate_arange_section: true,
             supports_stack_protector: true,
             entry_name: "main".into(),
-            entry_abi: Conv::C,
+            entry_abi: CanonAbi::C,
             supports_xray: false,
             small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch,
         }
@@ -2914,114 +2915,9 @@ impl DerefMut for Target {
 }
 
 impl Target {
-    /// Given a function ABI, turn it into the correct ABI for this target.
-    pub fn adjust_abi(&self, abi: ExternAbi, c_variadic: bool) -> ExternAbi {
-        use ExternAbi::*;
-        match abi {
-            // On Windows, `extern "system"` behaves like msvc's `__stdcall`.
-            // `__stdcall` only applies on x86 and on non-variadic functions:
-            // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
-            System { unwind } => {
-                if self.is_like_windows && self.arch == "x86" && !c_variadic {
-                    Stdcall { unwind }
-                } else {
-                    C { unwind }
-                }
-            }
-
-            EfiApi => {
-                if self.arch == "arm" {
-                    Aapcs { unwind: false }
-                } else if self.arch == "x86_64" {
-                    Win64 { unwind: false }
-                } else {
-                    C { unwind: false }
-                }
-            }
-
-            // See commentary in `is_abi_supported`.
-            Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => {
-                if self.arch == "x86" { abi } else { C { unwind } }
-            }
-            Vectorcall { unwind } => {
-                if ["x86", "x86_64"].contains(&&*self.arch) {
-                    abi
-                } else {
-                    C { unwind }
-                }
-            }
-
-            // The Windows x64 calling convention we use for `extern "Rust"`
-            // <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
-            // expects the callee to save `xmm6` through `xmm15`, but `PreserveMost`
-            // (that we use by default for `extern "rust-cold"`) doesn't save any of those.
-            // So to avoid bloating callers, just use the Rust convention here.
-            RustCold if self.is_like_windows && self.arch == "x86_64" => Rust,
-
-            abi => abi,
-        }
-    }
-
     pub fn is_abi_supported(&self, abi: ExternAbi) -> bool {
-        use ExternAbi::*;
-        match abi {
-            Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => {
-                true
-            }
-            EfiApi => {
-                ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
-            }
-            X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
-            Aapcs { .. } => "arm" == self.arch,
-            CCmseNonSecureCall | CCmseNonSecureEntry => {
-                ["thumbv8m.main-none-eabi", "thumbv8m.main-none-eabihf", "thumbv8m.base-none-eabi"]
-                    .contains(&&self.llvm_target[..])
-            }
-            Win64 { .. } | SysV64 { .. } => self.arch == "x86_64",
-            PtxKernel => self.arch == "nvptx64",
-            GpuKernel => ["amdgpu", "nvptx64"].contains(&&self.arch[..]),
-            Msp430Interrupt => self.arch == "msp430",
-            RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]),
-            AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
-            Thiscall { .. } => self.arch == "x86",
-            // On windows these fall-back to platform native calling convention (C) when the
-            // architecture is not supported.
-            //
-            // This is I believe a historical accident that has occurred as part of Microsoft
-            // striving to allow most of the code to "just" compile when support for 64-bit x86
-            // was added and then later again, when support for ARM architectures was added.
-            //
-            // This is well documented across MSDN. Support for this in Rust has been added in
-            // #54576. This makes much more sense in context of Microsoft's C++ than it does in
-            // Rust, but there isn't much leeway remaining here to change it back at the time this
-            // comment has been written.
-            //
-            // Following are the relevant excerpts from the MSDN documentation.
-            //
-            // > The __vectorcall calling convention is only supported in native code on x86 and
-            // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above.
-            // > ...
-            // > On ARM machines, __vectorcall is accepted and ignored by the compiler.
-            //
-            // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160
-            //
-            // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler;
-            //
-            // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160
-            //
-            // > In most cases, keywords or compiler switches that specify an unsupported
-            // > convention on a particular platform are ignored, and the platform default
-            // > convention is used.
-            //
-            // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
-            Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
-            // Outside of Windows we want to only support these calling conventions for the
-            // architectures for which these calling conventions are actually well defined.
-            Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
-            Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
-            // Reject these calling conventions everywhere else.
-            Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => false,
-        }
+        let abi_map = AbiMap::from_target(self);
+        abi_map.canonize_abi(abi, false).is_mapped()
     }
 
     /// Minimum integer size in bits that this target can perform atomic
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
index 07f853dacaf..0cf6a879462 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
@@ -5,7 +5,8 @@
 // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::callconv::Conv;
+use rustc_abi::{CanonAbi, X86Call};
+
 use crate::spec::{RustcAbi, Target, TargetMetadata, base};
 
 pub(crate) fn target() -> Target {
@@ -13,7 +14,7 @@ pub(crate) fn target() -> Target {
     base.cpu = "x86-64".into();
     base.plt_by_default = false;
     base.max_atomic_width = Some(64);
-    base.entry_abi = Conv::X86_64Win64;
+    base.entry_abi = CanonAbi::X86(X86Call::Win64);
 
     // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
     // enable these CPU features explicitly before their first use, otherwise their instructions
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 2b49d7ac8b5..83d7416b03e 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt};
 use rustc_session::config::OptLevel;
 use rustc_span::def_id::DefId;
 use rustc_target::callconv::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind,
+    AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode,
 };
 use tracing::debug;
 
@@ -240,45 +240,6 @@ fn fn_sig_for_fn_abi<'tcx>(
     }
 }
 
-#[inline]
-fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv {
-    use rustc_abi::ExternAbi::*;
-    match tcx.sess.target.adjust_abi(abi, c_variadic) {
-        Rust | RustCall => Conv::Rust,
-
-        // This is intentionally not using `Conv::Cold`, as that has to preserve
-        // even SIMD registers, which is generally not a good trade-off.
-        RustCold => Conv::PreserveMost,
-
-        // It's the ABI's job to select this, not ours.
-        System { .. } => bug!("system abi should be selected elsewhere"),
-        EfiApi => bug!("eficall abi should be selected elsewhere"),
-
-        Stdcall { .. } => Conv::X86Stdcall,
-        Fastcall { .. } => Conv::X86Fastcall,
-        Vectorcall { .. } => Conv::X86VectorCall,
-        Thiscall { .. } => Conv::X86ThisCall,
-        C { .. } => Conv::C,
-        Unadjusted => Conv::C,
-        Win64 { .. } => Conv::X86_64Win64,
-        SysV64 { .. } => Conv::X86_64SysV,
-        Aapcs { .. } => Conv::ArmAapcs,
-        CCmseNonSecureCall => Conv::CCmseNonSecureCall,
-        CCmseNonSecureEntry => Conv::CCmseNonSecureEntry,
-        PtxKernel => Conv::GpuKernel,
-        Msp430Interrupt => Conv::Msp430Intr,
-        X86Interrupt => Conv::X86Intr,
-        GpuKernel => Conv::GpuKernel,
-        AvrInterrupt => Conv::AvrInterrupt,
-        AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
-        RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine },
-        RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor },
-
-        // These API constants ought to be more specific...
-        Cdecl { .. } => Conv::C,
-    }
-}
-
 fn fn_abi_of_fn_ptr<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
@@ -529,7 +490,8 @@ fn fn_abi_new_uncached<'tcx>(
     };
     let sig = tcx.normalize_erasing_regions(cx.typing_env, sig);
 
-    let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
+    let abi_map = AbiMap::from_target(&tcx.sess.target);
+    let conv = abi_map.canonize_abi(sig.abi, sig.c_variadic).unwrap();
 
     let mut inputs = sig.inputs();
     let extra_args = if sig.abi == ExternAbi::RustCall {
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index dcc74b099d6..20ea239b7e5 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -3,7 +3,7 @@ use std::time::Duration;
 use std::{cmp, iter};
 
 use rand::RngCore;
-use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
+use rustc_abi::{Align, CanonAbi, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_hir::Safety;
@@ -18,7 +18,7 @@ use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
 use rustc_session::config::CrateType;
 use rustc_span::{Span, Symbol};
 use rustc_symbol_mangling::mangle_internal_symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -936,11 +936,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_callconv<'a>(
         &self,
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
     ) -> InterpResult<'a, ()> {
         if fn_abi.conv != exp_abi {
             throw_ub_format!(
-                "calling a function with calling convention {exp_abi} using caller calling convention {}",
+                r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#,
                 fn_abi.conv
             );
         }
@@ -973,7 +973,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_abi_and_shim_symbol_clash(
         &mut self,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
         link_name: Symbol,
     ) -> InterpResult<'tcx, ()> {
         self.check_callconv(abi, exp_abi)?;
@@ -998,7 +998,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_shim<'a, const N: usize>(
         &mut self,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
         link_name: Symbol,
         args: &'a [OpTy<'tcx>],
     ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
@@ -1098,7 +1098,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_shim_variadic<'a, const N: usize>(
         &mut self,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
         link_name: Symbol,
         args: &'a [OpTy<'tcx>],
     ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])>
diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs
index 7cccc9e51d8..44ad5081ad5 100644
--- a/src/tools/miri/src/shims/aarch64.rs
+++ b/src/tools/miri/src/shims/aarch64.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir::BinOp;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -19,7 +20,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.aarch64.").unwrap();
         match unprefixed_name {
             "isb" => {
-                let [arg] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let arg = this.read_scalar(arg)?.to_i32()?;
                 match arg {
                     // SY ("full system scope")
@@ -37,7 +38,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `left` input, the second half of the output from the `right` input.
             // https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxq_u8
             "neon.umaxp.v16i8" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 9f3bc06771f..ab11553df63 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,8 +1,8 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, Size};
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -16,7 +16,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let [flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+        let [flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
         if flags != 0 {
@@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
         let ptr_layout = this.layout_of(ptr_ty)?;
 
-        let [flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+        let [flags, buf] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
         let buf_place = this.deref_pointer_as(buf, ptr_layout)?;
@@ -118,7 +118,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let [ptr, flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+        let [ptr, flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
 
@@ -190,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let [ptr, flags, name_ptr, filename_ptr] =
-            this.check_shim(abi, Conv::Rust, link_name, args)?;
+            this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
         if flags != 0 {
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index b08b522d279..ae04ca018ab 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -2,7 +2,7 @@ use std::collections::hash_map::Entry;
 use std::io::Write;
 use std::path::Path;
 
-use rustc_abi::{Align, AlignFromBytesError, Size};
+use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size};
 use rustc_apfloat::Float;
 use rustc_ast::expand::allocator::alloc_error_handler_name;
 use rustc_hir::def::DefKind;
@@ -12,7 +12,7 @@ use rustc_middle::mir::interpret::AllocInit;
 use rustc_middle::ty::{Instance, Ty};
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::helpers::{ToHost, ToSoft};
 use super::alloc::EvalContextExt as _;
@@ -250,7 +250,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // When adding a new shim, you should follow the following pattern:
         // ```
         // "shim_name" => {
-        //     let [arg1, arg2, arg3] = this.check_shim(abi, Conv::::C , link_name, args)?;
+        //     let [arg1, arg2, arg3] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
         //     let result = this.shim_name(arg1, arg2, arg3)?;
         //     this.write_scalar(result, dest)?;
         // }
@@ -288,16 +288,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Miri-specific extern functions
             "miri_start_unwind" => {
-                let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [payload] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "miri_run_provenance_gc" => {
-                let [] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 this.run_provenance_gc();
             }
             "miri_get_alloc_id" => {
-                let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| {
                     err_machine_stop!(TerminationInfo::Abort(format!(
@@ -307,7 +307,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
             }
             "miri_print_borrow_state" => {
-                let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [id, show_unnamed] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let id = this.read_scalar(id)?.to_u64()?;
                 let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
                 if let Some(id) = std::num::NonZero::new(id).map(AllocId)
@@ -321,7 +321,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_pointer_name" => {
                 // This associates a name to a tag. Very useful for debugging, and also makes
                 // tests more strict.
-                let [ptr, nth_parent, name] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr, nth_parent, name] =
+                    this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nth_parent = this.read_scalar(nth_parent)?.to_u8()?;
                 let name = this.read_immediate(name)?;
@@ -334,7 +335,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.give_pointer_debug_name(ptr, nth_parent, &name)?;
             }
             "miri_static_root" => {
-                let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?;
                 if offset != Size::ZERO {
@@ -345,7 +346,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.machine.static_roots.push(alloc_id);
             }
             "miri_host_to_target_path" => {
-                let [ptr, out, out_size] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr, out, out_size] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let out = this.read_pointer(out)?;
                 let out_size = this.read_scalar(out_size)?.to_target_usize(this)?;
@@ -381,7 +382,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Writes some bytes to the interpreter's stdout/stderr. See the
             // README for details.
             "miri_write_to_stdout" | "miri_write_to_stderr" => {
-                let [msg] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [msg] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let msg = this.read_immediate(msg)?;
                 let msg = this.read_byte_slice(&msg)?;
                 // Note: we're ignoring errors writing to host stdout/stderr.
@@ -395,7 +396,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_promise_symbolic_alignment" => {
                 use rustc_abi::AlignFromBytesError;
 
-                let [ptr, align] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let align = this.read_target_usize(align)?;
                 if !align.is_power_of_two() {
@@ -436,12 +437,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Aborting the process.
             "exit" => {
-                let [code] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [code] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let code = this.read_scalar(code)?.to_i32()?;
                 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
             }
             "abort" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 throw_machine_stop!(TerminationInfo::Abort(
                     "the program aborted execution".to_owned()
                 ))
@@ -449,7 +450,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Standard C allocation
             "malloc" => {
-                let [size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let size = this.read_target_usize(size)?;
                 if size <= this.max_size_of_val().bytes() {
                     let res = this.malloc(size, AllocInit::Uninit)?;
@@ -463,7 +464,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "calloc" => {
-                let [items, elem_size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [items, elem_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let items = this.read_target_usize(items)?;
                 let elem_size = this.read_target_usize(elem_size)?;
                 if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) {
@@ -478,12 +479,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "free" => {
-                let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 this.free(ptr)?;
             }
             "realloc" => {
-                let [old_ptr, new_size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [old_ptr, new_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let old_ptr = this.read_pointer(old_ptr)?;
                 let new_size = this.read_target_usize(new_size)?;
                 if new_size <= this.max_size_of_val().bytes() {
@@ -503,7 +504,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let default = |ecx: &mut MiriInterpCx<'tcx>| {
                     // Only call `check_shim` when `#[global_allocator]` isn't used. When that
                     // macro is used, we act like no shim exists, so that the exported function can run.
-                    let [size, align] = ecx.check_shim(abi, Conv::Rust, link_name, args)?;
+                    let [size, align] = ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let size = ecx.read_target_usize(size)?;
                     let align = ecx.read_target_usize(align)?;
 
@@ -536,7 +537,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 return this.emulate_allocator(|this| {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
-                    let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                    let [size, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let size = this.read_target_usize(size)?;
                     let align = this.read_target_usize(align)?;
 
@@ -558,7 +559,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
                     let [ptr, old_size, align] =
-                        ecx.check_shim(abi, Conv::Rust, link_name, args)?;
+                        ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let ptr = ecx.read_pointer(ptr)?;
                     let old_size = ecx.read_target_usize(old_size)?;
                     let align = ecx.read_target_usize(align)?;
@@ -589,7 +590,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
                     let [ptr, old_size, align, new_size] =
-                        this.check_shim(abi, Conv::Rust, link_name, args)?;
+                        this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let ptr = this.read_pointer(ptr)?;
                     let old_size = this.read_target_usize(old_size)?;
                     let align = this.read_target_usize(align)?;
@@ -613,7 +614,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // C memory handling functions
             "memcmp" => {
-                let [left, right, n] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let left = this.read_pointer(left)?;
                 let right = this.read_pointer(right)?;
                 let n = Size::from_bytes(this.read_target_usize(n)?);
@@ -637,7 +638,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
             "memrchr" => {
-                let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_target_usize(num)?;
@@ -663,7 +664,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "memchr" => {
-                let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_target_usize(num)?;
@@ -686,7 +687,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "strlen" => {
-                let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 // This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
                 let n = this.read_c_str(ptr)?.len();
@@ -696,7 +697,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 )?;
             }
             "wcslen" => {
-                let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 // This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
                 let n = this.read_wchar_t_str(ptr)?.len();
@@ -706,7 +707,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 )?;
             }
             "memcpy" => {
-                let [ptr_dest, ptr_src, n] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr_dest, ptr_src, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr_dest = this.read_pointer(ptr_dest)?;
                 let ptr_src = this.read_pointer(ptr_src)?;
                 let n = this.read_target_usize(n)?;
@@ -720,7 +721,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_pointer(ptr_dest, dest)?;
             }
             "strcpy" => {
-                let [ptr_dest, ptr_src] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr_dest, ptr_src] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr_dest = this.read_pointer(ptr_dest)?;
                 let ptr_src = this.read_pointer(ptr_src)?;
 
@@ -751,7 +752,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "erff"
             | "erfcf"
             => {
-                let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let f_host = f.to_host();
@@ -789,7 +790,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "atan2f"
             | "fdimf"
             => {
-                let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
                 // underscore case for windows, here and below
@@ -828,7 +829,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "erf"
             | "erfc"
             => {
-                let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let f_host = f.to_host();
@@ -866,7 +867,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "atan2"
             | "fdim"
             => {
-                let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
                 // underscore case for windows, here and below
@@ -895,7 +896,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "ldexp"
             | "scalbn"
             => {
-                let [x, exp] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [x, exp] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
                 let x = this.read_scalar(x)?.to_f64()?;
                 let exp = this.read_scalar(exp)?.to_i32()?;
@@ -905,7 +906,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "lgammaf_r" => {
-                let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let x = this.read_scalar(x)?.to_f32()?;
                 let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
 
@@ -921,7 +922,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "lgamma_r" => {
-                let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let x = this.read_scalar(x)?.to_f64()?;
                 let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
 
@@ -939,7 +940,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // LLVM intrinsics
             "llvm.prefetch" => {
-                let [p, rw, loc, ty] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [p, rw, loc, ty] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let _ = this.read_pointer(p)?;
                 let rw = this.read_scalar(rw)?.to_i32()?;
@@ -966,7 +967,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm
             // `{i,u}8x16_popcnt` functions.
             name if name.starts_with("llvm.ctpop.v") => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (op, op_len) = this.project_to_simd(op)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -1002,7 +1003,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // FIXME: Move this to an `arm` submodule.
             "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
-                let [arg] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let arg = this.read_scalar(arg)?.to_i32()?;
                 // Note that different arguments might have different target feature requirements.
                 match arg {
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 0e7cf7153f5..690b5295681 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::shims::unix::android::thread::prctl;
 use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -25,29 +26,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // epoll, eventfd
             "epoll_create1" => {
-                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_create1(flag)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_ctl" => {
-                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_wait" => {
                 let [epfd, events, maxevents, timeout] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
             }
             "eventfd" => {
-                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.eventfd(val, flag)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Miscellaneous
             "__errno" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index aa3a05ead85..5d17d6c8517 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -1,7 +1,7 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, Size};
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
@@ -16,7 +16,7 @@ pub fn prctl<'tcx>(
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
-    let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?;
+    let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
 
     // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
     let pr_set_name = 15;
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 026aa1f9503..9106ef94c43 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -1,11 +1,11 @@
 use std::ffi::OsStr;
 use std::str;
 
-use rustc_abi::{ExternAbi, Size};
+use rustc_abi::{CanonAbi, ExternAbi, Size};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::shims::unix::android::foreign_items as android;
 use self::shims::unix::freebsd::foreign_items as freebsd;
@@ -334,7 +334,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "fcntl" => {
                 let ([fd_num, cmd], varargs) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let result = this.fcntl(fd_num, cmd, varargs)?;
                 this.write_scalar(result, dest)?;
             }
@@ -387,7 +387,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // `open` is variadic, the third argument is only present when the second argument
                 // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
                 let ([path_raw, flag], varargs) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let result = this.open(path_raw, flag, varargs)?;
                 this.write_scalar(result, dest)?;
             }
@@ -701,20 +701,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Allocation
             "posix_memalign" => {
-                let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.posix_memalign(memptr, align, size)?;
                 this.write_scalar(result, dest)?;
             }
 
             "mmap" => {
                 let [addr, length, prot, flags, fd, offset] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
                 this.write_scalar(ptr, dest)?;
             }
             "munmap" => {
-                let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [addr, length] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.munmap(addr, length)?;
                 this.write_scalar(result, dest)?;
             }
@@ -722,7 +722,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "reallocarray" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
-                let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, nmemb, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nmemb = this.read_target_usize(nmemb)?;
                 let size = this.read_target_usize(size)?;
@@ -745,14 +745,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "aligned_alloc" => {
                 // This is a C11 function, we assume all Unixes have it.
                 // (MSVC explicitly does not support this.)
-                let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = this.aligned_alloc(align, size)?;
                 this.write_pointer(res, dest)?;
             }
 
             // Dynamic symbol loading
             "dlsym" => {
-                let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [handle, symbol] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.read_target_usize(handle)?;
                 let symbol = this.read_pointer(symbol)?;
                 let name = this.read_c_str(symbol)?;
@@ -768,7 +768,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Thread-local storage
             "pthread_key_create" => {
-                let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [key, dtor] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
                 let dtor = this.read_pointer(dtor)?;
 
@@ -796,21 +796,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
             "pthread_key_delete" => {
-                let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 this.machine.tls.delete_tls_key(key)?;
                 // Return success (0)
                 this.write_null(dest)?;
             }
             "pthread_getspecific" => {
-                let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 let active_thread = this.active_thread();
                 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
                 this.write_scalar(ptr, dest)?;
             }
             "pthread_setspecific" => {
-                let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [key, new_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 let active_thread = this.active_thread();
                 let new_data = this.read_scalar(new_ptr)?;
@@ -822,156 +822,157 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Synchronization primitives
             "pthread_mutexattr_init" => {
-                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_mutexattr_init(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutexattr_settype" => {
-                let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr, kind] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.pthread_mutexattr_settype(attr, kind)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutexattr_destroy" => {
-                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_mutexattr_destroy(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutex_init" => {
-                let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [mutex, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_mutex_init(mutex, attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutex_lock" => {
-                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_mutex_lock(mutex, dest)?;
             }
             "pthread_mutex_trylock" => {
-                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.pthread_mutex_trylock(mutex)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutex_unlock" => {
-                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.pthread_mutex_unlock(mutex)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutex_destroy" => {
-                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_mutex_destroy(mutex)?;
                 this.write_int(0, dest)?;
             }
             "pthread_rwlock_rdlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_rwlock_rdlock(rwlock, dest)?;
             }
             "pthread_rwlock_tryrdlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_wrlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_rwlock_wrlock(rwlock, dest)?;
             }
             "pthread_rwlock_trywrlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.pthread_rwlock_trywrlock(rwlock)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_unlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_rwlock_unlock(rwlock)?;
                 this.write_null(dest)?;
             }
             "pthread_rwlock_destroy" => {
-                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_rwlock_destroy(rwlock)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_init" => {
-                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_condattr_init(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_setclock" => {
-                let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.pthread_condattr_setclock(attr, clock_id)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_condattr_getclock" => {
-                let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_condattr_getclock(attr, clock_id)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_destroy" => {
-                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_condattr_destroy(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_init" => {
-                let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cond, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_cond_init(cond, attr)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_signal" => {
-                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_cond_signal(cond)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_broadcast" => {
-                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_cond_broadcast(cond)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_wait" => {
-                let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cond, mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_cond_wait(cond, mutex, dest)?;
             }
             "pthread_cond_timedwait" => {
-                let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cond, mutex, abstime] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
             }
             "pthread_cond_destroy" => {
-                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_cond_destroy(cond)?;
                 this.write_null(dest)?;
             }
 
             // Threading
             "pthread_create" => {
-                let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, attr, start, arg] =
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.pthread_create(thread, attr, start, arg)?;
                 this.write_null(dest)?;
             }
             "pthread_join" => {
-                let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, retval] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = this.pthread_join(thread, retval)?;
                 this.write_scalar(res, dest)?;
             }
             "pthread_detach" => {
-                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = this.pthread_detach(thread)?;
                 this.write_scalar(res, dest)?;
             }
             "pthread_self" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = this.pthread_self()?;
                 this.write_scalar(res, dest)?;
             }
             "sched_yield" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.sched_yield()?;
                 this.write_null(dest)?;
             }
             "nanosleep" => {
-                let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [req, rem] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.nanosleep(req, rem)?;
                 this.write_scalar(result, dest)?;
             }
             "sched_getaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
-                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
                 let mask = this.read_pointer(mask)?;
@@ -1008,7 +1009,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "sched_setaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
-                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
                 let mask = this.read_pointer(mask)?;
@@ -1048,12 +1049,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Miscellaneous
             "isatty" => {
-                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.isatty(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_atfork" => {
-                let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [prepare, parent, child] =
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.read_pointer(prepare)?;
                 this.read_pointer(parent)?;
                 this.read_pointer(child)?;
@@ -1067,7 +1069,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     &["linux", "macos", "freebsd", "illumos", "solaris", "android"],
                     link_name,
                 )?;
-                let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let buf = this.read_pointer(buf)?;
                 let bufsize = this.read_target_usize(bufsize)?;
 
@@ -1085,7 +1087,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "strerror_r" => {
-                let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.strerror_r(errnum, buf, buflen)?;
                 this.write_scalar(result, dest)?;
             }
@@ -1097,7 +1099,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     &["linux", "freebsd", "illumos", "solaris", "android"],
                     link_name,
                 )?;
-                let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, len, flags] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 let _flags = this.read_scalar(flags)?.to_i32()?;
@@ -1109,7 +1111,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This function is non-standard but exists with the same signature and
                 // same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
                 this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?;
-                let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 this.gen_random(ptr, len)?;
@@ -1133,12 +1135,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     link_name,
                 )?;
                 // This function looks and behaves excatly like miri_start_unwind.
-                let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "getuid" | "geteuid" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // For now, just pretend we always have this fixed UID.
                 this.write_int(UID, dest)?;
             }
@@ -1146,7 +1148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
             "pthread_attr_getguardsize" if this.frame_in_std() => {
-                let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_attr, guard_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let guard_size_layout = this.machine.layouts.usize;
                 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
                 this.write_scalar(
@@ -1159,11 +1161,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
-                let [_] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
             "pthread_attr_setstacksize" if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
@@ -1171,7 +1173,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
                 // Hence we can mostly ignore the input `attr_place`.
                 let [attr_place, addr_place, size_place] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let _attr_place =
                     this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
                 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
@@ -1191,18 +1193,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "signal" | "sigaltstack" if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
             "sigaction" | "mprotect" if this.frame_in_std() => {
-                let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_, _, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
             "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
                 // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
                 let [uid, pwd, buf, buflen, result] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.check_no_isolation("`getpwuid_r`")?;
 
                 let uid = this.read_scalar(uid)?.to_u32()?;
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 533a741fea3..42502d5bf09 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::sync::EvalContextExt as _;
 use crate::shims::unix::*;
@@ -23,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Threading
             "pthread_setname_np" => {
-                let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let max_len = u64::MAX; // FreeBSD does not seem to have a limit.
                 let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
@@ -38,7 +39,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value,
                 // but always adds a null terminator (except for zero-sized buffers).
                 // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144
@@ -59,7 +60,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "cpuset_getaffinity" => {
                 // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically.
                 let [level, which, id, set_size, mask] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let level = this.read_scalar(level)?.to_i32()?;
                 let which = this.read_scalar(which)?.to_i32()?;
@@ -123,7 +124,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Synchronization primitives
             "_umtx_op" => {
                 let [obj, op, val, uaddr, uaddr2] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?;
             }
 
@@ -131,29 +132,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
             // since freebsd 12 the former form can be expected.
             "stat" | "stat@FBSD_1.0" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat@FBSD_1.0" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat@FBSD_1.0" => {
-                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir_r" | "readdir_r@FBSD_1.0" => {
-                let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Miscellaneous
             "__error" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
@@ -161,7 +162,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
             "pthread_attr_get_np" if this.frame_in_std() => {
-                let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 51c2434d68a..aeaff1cb13a 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::shims::unix::linux::mem::EvalContextExt as _;
 use self::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -36,47 +37,48 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // File related shims
             "readdir64" => {
-                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_solarish_readdir64("dirent64", dirp)?;
                 this.write_scalar(result, dest)?;
             }
             "sync_file_range" => {
-                let [fd, offset, nbytes, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, offset, nbytes, flags] =
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.sync_file_range(fd, offset, nbytes, flags)?;
                 this.write_scalar(result, dest)?;
             }
             "statx" => {
                 let [dirfd, pathname, flags, mask, statxbuf] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
                 this.write_scalar(result, dest)?;
             }
 
             // epoll, eventfd
             "epoll_create1" => {
-                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_create1(flag)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_ctl" => {
-                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_wait" => {
                 let [epfd, events, maxevents, timeout] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
             }
             "eventfd" => {
-                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.eventfd(val, flag)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Threading
             "pthread_setname_np" => {
-                let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
@@ -91,7 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // The function's behavior isn't portable between platforms.
                 // In case of glibc, the length of the output buffer must
                 // be not shorter than TASK_COMM_LEN.
@@ -114,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "gettid" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_gettid()?;
                 this.write_scalar(result, dest)?;
             }
@@ -127,34 +129,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Miscellaneous
             "mmap64" => {
                 let [addr, length, prot, flags, fd, offset] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let offset = this.read_scalar(offset)?.to_i64()?;
                 let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
                 this.write_scalar(ptr, dest)?;
             }
             "mremap" => {
                 let ([old_address, old_size, new_size, flags], _) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.mremap(old_address, old_size, new_size, flags)?;
                 this.write_scalar(ptr, dest)?;
             }
             "__xpg_strerror_r" => {
-                let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.strerror_r(errnum, buf, buflen)?;
                 this.write_scalar(result, dest)?;
             }
             "__errno_location" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
             "__libc_current_sigrtmin" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 this.write_int(SIGRTMIN, dest)?;
             }
             "__libc_current_sigrtmax" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 this.write_int(SIGRTMAX, dest)?;
             }
@@ -162,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
             "pthread_getattr_np" if this.frame_in_std() => {
-                let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
index 22c6dc97507..d42d6b9073e 100644
--- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
@@ -14,7 +15,7 @@ pub fn syscall<'tcx>(
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
-    let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?;
+    let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
     // The syscall variadic function is legal to call with more arguments than needed,
     // extra arguments are simply ignored. The important check is that when we use an
     // argument, we have to also check all arguments *before* it to ensure that they
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 0281bb9f71d..ae921a013a4 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::sync::{EvalContextExt as _, MacOsFutexTimeout};
 use crate::shims::unix::*;
@@ -34,64 +35,64 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // errno
             "__error" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
             // File related shims
             "close$NOCANCEL" => {
-                let [result] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.close(result)?;
                 this.write_scalar(result, dest)?;
             }
             "stat" | "stat64" | "stat$INODE64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat64" | "lstat$INODE64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat64" | "fstat$INODE64" => {
-                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "opendir$INODE64" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.opendir(name)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir_r" | "readdir_r$INODE64" => {
-                let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
                 this.write_scalar(result, dest)?;
             }
             "realpath$DARWIN_EXTSN" => {
-                let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, resolved_path] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
             "ioctl" => {
                 let ([fd_num, cmd], varargs) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let result = this.ioctl(fd_num, cmd, varargs)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Environment related shims
             "_NSGetEnviron" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let environ = this.machine.env_vars.unix().environ();
                 this.write_pointer(environ, dest)?;
             }
 
             // Random data generation
             "CCRandomGenerateBytes" => {
-                let [bytes, count] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [bytes, count] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let bytes = this.read_pointer(bytes)?;
                 let count = this.read_target_usize(count)?;
                 let success = this.eval_libc_i32("kCCSuccess");
@@ -101,28 +102,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Time related shims
             "mach_absolute_time" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.mach_absolute_time()?;
                 this.write_scalar(result, dest)?;
             }
 
             "mach_timebase_info" => {
-                let [info] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [info] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.mach_timebase_info(info)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Access to command-line arguments
             "_NSGetArgc" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
             }
             "_NSGetArgv" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
             }
             "_NSGetExecutablePath" => {
-                let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.check_no_isolation("`_NSGetExecutablePath`")?;
 
                 let buf_ptr = this.read_pointer(buf)?;
@@ -147,7 +148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Thread-local storage
             "_tlv_atexit" => {
-                let [dtor, data] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dtor, data] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let dtor = this.read_pointer(dtor)?;
                 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
                 let data = this.read_scalar(data)?;
@@ -157,13 +158,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Querying system information
             "pthread_get_stackaddr_np" => {
-                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.read_target_usize(thread)?;
                 let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
                 this.write_scalar(stack_addr, dest)?;
             }
             "pthread_get_stacksize_np" => {
-                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.read_target_usize(thread)?;
                 let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
                 this.write_scalar(stack_size, dest)?;
@@ -171,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Threading
             "pthread_setname_np" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 // The real implementation has logic in two places:
                 // * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200,
@@ -198,7 +199,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 // The function's behavior isn't portable between platforms.
                 // In case of macOS, a truncated name (due to a too small buffer)
@@ -225,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Synchronization primitives
             "os_sync_wait_on_address" => {
                 let [addr_op, value_op, size_op, flags_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wait_on_address(
                     addr_op,
                     value_op,
@@ -237,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "os_sync_wait_on_address_with_deadline" => {
                 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wait_on_address(
                     addr_op,
                     value_op,
@@ -249,7 +250,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "os_sync_wait_on_address_with_timeout" => {
                 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wait_on_address(
                     addr_op,
                     value_op,
@@ -261,36 +262,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "os_sync_wake_by_address_any" => {
                 let [addr_op, size_op, flags_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wake_by_address(
                     addr_op, size_op, flags_op, /* all */ false, dest,
                 )?;
             }
             "os_sync_wake_by_address_all" => {
                 let [addr_op, size_op, flags_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wake_by_address(
                     addr_op, size_op, flags_op, /* all */ true, dest,
                 )?;
             }
             "os_unfair_lock_lock" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_lock(lock_op)?;
             }
             "os_unfair_lock_trylock" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_trylock(lock_op, dest)?;
             }
             "os_unfair_lock_unlock" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_unlock(lock_op)?;
             }
             "os_unfair_lock_assert_owner" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_assert_owner(lock_op)?;
             }
             "os_unfair_lock_assert_not_owner" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_assert_not_owner(lock_op)?;
             }
 
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index 21d4f41f485..e3d15b89be6 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::shims::unix::foreign_items::EvalContextExt as _;
 use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -26,32 +27,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // epoll, eventfd (NOT available on Solaris!)
             "epoll_create1" => {
                 this.assert_target_os("illumos", "epoll_create1");
-                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_create1(flag)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_ctl" => {
                 this.assert_target_os("illumos", "epoll_ctl");
-                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_wait" => {
                 this.assert_target_os("illumos", "epoll_wait");
                 let [epfd, events, maxevents, timeout] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
             }
             "eventfd" => {
                 this.assert_target_os("illumos", "eventfd");
-                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.eventfd(val, flag)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Threading
             "pthread_setname_np" => {
-                let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // THREAD_NAME_MAX allows a thread name of 31+1 length
                 // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613
                 let max_len = 32;
@@ -69,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // See https://illumos.org/man/3C/pthread_getname_np for the error codes.
                 let res = match this.pthread_getname_np(
                     this.read_scalar(thread)?,
@@ -86,22 +87,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // File related shims
             "stat" | "stat64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat64" => {
-                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir" => {
-                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_solarish_readdir64("dirent", dirp)?;
                 this.write_scalar(result, dest)?;
             }
@@ -109,20 +110,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Sockets and pipes
             "__xnet_socketpair" => {
                 let [domain, type_, protocol, sv] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.socketpair(domain, type_, protocol, sv)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Miscellaneous
             "___errno" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
             "stack_getbounds" => {
-                let [stack] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [stack] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?;
 
                 this.write_int_fields_named(
@@ -140,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "pset_info" => {
-                let [pset, tpe, cpus, list] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pset, tpe, cpus, list] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // We do not need to handle the current process cpu mask, available_parallelism
                 // implementation pass null anyway. We only care for the number of
                 // cpus.
@@ -169,7 +170,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "__sysconf_xpg7" => {
-                let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.sysconf(val)?;
                 this.write_scalar(result, dest)?;
             }
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
index 90de62b9e57..8d92d0f3381 100644
--- a/src/tools/miri/src/shims/wasi/foreign_items.rs
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::shims::alloc::EvalContextExt as _;
 use crate::*;
@@ -22,12 +23,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Allocation
             "posix_memalign" => {
-                let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.posix_memalign(memptr, align, size)?;
                 this.write_scalar(result, dest)?;
             }
             "aligned_alloc" => {
-                let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = this.aligned_alloc(align, size)?;
                 this.write_pointer(res, dest)?;
             }
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 98099e07b2e..10f6df67ad4 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -2,10 +2,10 @@ use std::ffi::OsStr;
 use std::path::{self, Path, PathBuf};
 use std::{io, iter, str};
 
-use rustc_abi::{Align, Size};
+use rustc_abi::{Align, CanonAbi, Size, X86Call};
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::shims::windows::handle::{Handle, PseudoHandle};
 use crate::shims::os_str::bytes_to_os_str;
@@ -140,7 +140,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768,
         // x86-32 Windows uses a different calling convention than other Windows targets
         // for the "system" ABI.
-        let sys_conv = if this.tcx.sess.target.arch == "x86" { Conv::X86Stdcall } else { Conv::C };
+        let sys_conv = if this.tcx.sess.target.arch == "x86" {
+            CanonAbi::X86(X86Call::Stdcall)
+        } else {
+            CanonAbi::C
+        };
 
         // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
 
@@ -856,7 +860,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
                 // This function looks and behaves excatly like miri_start_unwind.
-                let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index c6784db67fb..7191284b5a3 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -26,7 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128
             "aesdec" | "aesdec.256" | "aesdec.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 aes_round(this, state, key, dest, |state, key| {
                     let key = aes::Block::from(key.to_le_bytes());
                     let mut state = aes::Block::from(state.to_le_bytes());
@@ -42,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128
             "aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 aes_round(this, state, key, dest, |state, key| {
                     let mut state = aes::Block::from(state.to_le_bytes());
@@ -66,7 +67,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128
             "aesenc" | "aesenc.256" | "aesenc.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 aes_round(this, state, key, dest, |state, key| {
                     let key = aes::Block::from(key.to_le_bytes());
                     let mut state = aes::Block::from(state.to_le_bytes());
@@ -82,7 +83,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128
             "aesenclast" | "aesenclast.256" | "aesenclast.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 aes_round(this, state, key, dest, |state, key| {
                     let mut state = aes::Block::from(state.to_le_bytes());
                     // `aes::hazmat::cipher_round` does the following operations:
@@ -102,7 +103,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm_aesimc_si128 function.
             // Performs the AES InvMixColumns operation on `op`
             "aesimc" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // Transmute to `u128`
                 let op = op.transmute(this.machine.layouts.u128, this)?;
                 let dest = dest.transmute(this.machine.layouts.u128, this)?;
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 3aeb2b429da..37539fec748 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -1,9 +1,10 @@
+use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, conditional_dot_product, convert_float_to_int,
@@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.ps.256" | "max.ps.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.ps.256" => FloatBinOp::Min,
@@ -45,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement _mm256_min_pd and _mm256_max_pd functions.
             "min.pd.256" | "max.pd.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.pd.256" => FloatBinOp::Min,
@@ -58,21 +59,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm256_round_ps function.
             // Rounds the elements of `op` according to `rounding`.
             "round.ps.256" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
             }
             // Used to implement the _mm256_round_pd function.
             // Rounds the elements of `op` according to `rounding`.
             "round.pd.256" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
             }
             // Used to implement _mm256_{rcp,rsqrt}_ps functions.
             // Performs the operations on all components of `op`.
             "rcp.ps.256" | "rsqrt.ps.256" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "rcp.ps.256" => FloatUnaryOp::Rcp,
@@ -84,7 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement the _mm256_dp_ps function.
             "dp.ps.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 conditional_dot_product(this, left, right, imm, dest)?;
             }
@@ -92,7 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Horizontally add/subtract adjacent floating point values
             // in `left` and `right`.
             "hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add,
@@ -107,7 +108,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and `right`. For each component, returns 0 if false or u32::MAX
             // if true.
             "cmp.ps.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -119,7 +120,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and `right`. For each component, returns 0 if false or u64::MAX
             // if true.
             "cmp.pd.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -130,7 +131,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and _mm256_cvttpd_epi32 functions.
             // Converts packed f32/f64 to packed i32.
             "cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
@@ -148,7 +149,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // sequence of 4-element arrays, and we shuffle each of these arrays, where
             // `control` determines which element of the current `data` array is written.
             "vpermilvar.ps" | "vpermilvar.ps.256" => {
-                let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (data, data_len) = this.project_to_simd(data)?;
                 let (control, control_len) = this.project_to_simd(control)?;
@@ -181,7 +182,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // where `right` determines which element of the current `left` array is
             // written.
             "vpermilvar.pd" | "vpermilvar.pd.256" => {
-                let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (data, data_len) = this.project_to_simd(data)?;
                 let (control, control_len) = this.project_to_simd(control)?;
@@ -213,7 +214,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // For each 128-bit element of `dest`, copies one from `left`, `right` or
             // zero, according to `imm`.
             "vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 assert_eq!(dest.layout, left.layout);
                 assert_eq!(dest.layout, right.layout);
@@ -256,7 +257,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
             // loaded.
             "maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => {
-                let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_load(this, ptr, mask, dest)?;
             }
@@ -266,7 +267,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is stored into `ptr.wapping_add(i)`.
             // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
             "maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => {
-                let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_store(this, ptr, mask, value)?;
             }
@@ -276,7 +277,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the data crosses a cache line, but for Miri this is just a regular
             // unaligned read.
             "ldu.dq.256" => {
-                let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let src_ptr = this.read_pointer(src_ptr)?;
                 let dest = dest.force_mplace(this)?;
 
@@ -288,7 +289,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Tests `op & mask == 0`, `op & mask == mask` or
             // `op & mask != 0 && op & mask != mask`
             "ptestz.256" | "ptestc.256" | "ptestnzc.256" => {
-                let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
                 let res = match unprefixed_name {
@@ -311,7 +312,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestz.pd" | "vtestc.pd"
             | "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256"
             | "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => {
-                let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (direct, negated) = test_high_bits_masked(this, op, mask)?;
                 let res = match unprefixed_name {
@@ -333,7 +334,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // compiler, making these functions no-ops.
 
                 // The only thing that needs to be ensured is the correct calling convention.
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
             }
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index c79899285cd..5dfe5cc2c54 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -1,8 +1,9 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     ShiftOp, horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb,
@@ -28,7 +29,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm256_abs_epi{8,16,32} functions.
             // Calculates the absolute value of packed 8/16/32-bit integers.
             "pabs.b" | "pabs.w" | "pabs.d" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 int_abs(this, op, dest)?;
             }
@@ -36,7 +37,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Horizontally add / add with saturation / subtract adjacent 16/32-bit
             // integer values in `left` and `right`.
             "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (which, saturating) = match unprefixed_name {
                     "phadd.w" | "phadd.d" => (mir::BinOp::Add, false),
@@ -57,7 +58,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps"
             | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => {
                 let [src, slice, offsets, mask, scale] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 assert_eq!(dest.layout, src.layout);
 
@@ -114,7 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // intermediate signed 32-bit integers. Horizontally add adjacent pairs of
             // intermediate 32-bit integers, and pack the results in `dest`.
             "pmadd.wd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -150,7 +151,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the saturating sum of the products with indices `2*i` and `2*i+1`
             // produces the output at index `i`.
             "pmadd.ub.sw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -184,7 +185,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
             // loaded.
             "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => {
-                let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_load(this, ptr, mask, dest)?;
             }
@@ -194,7 +195,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is stored into `ptr.wapping_add(i)`.
             // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
             "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => {
-                let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_store(this, ptr, mask, value)?;
             }
@@ -205,7 +206,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // offsets specified in `imm`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8
             "mpsadbw" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mpsadbw(this, left, right, imm, dest)?;
             }
@@ -216,7 +217,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 1 and then taking the bits `1..=16`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16
             "pmul.hr.sw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 pmulhrsw(this, left, right, dest)?;
             }
@@ -224,7 +225,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit integer vectors to a single 8-bit integer
             // vector with signed saturation.
             "packsswb" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packsswb(this, left, right, dest)?;
             }
@@ -232,7 +233,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 32-bit integer vectors to a single 16-bit integer
             // vector with signed saturation.
             "packssdw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packssdw(this, left, right, dest)?;
             }
@@ -240,7 +241,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit signed integer vectors to a single 8-bit
             // unsigned integer vector with saturation.
             "packuswb" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packuswb(this, left, right, dest)?;
             }
@@ -248,7 +249,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Concatenates two 32-bit signed integer vectors and converts
             // the result to a 16-bit unsigned integer vector with saturation.
             "packusdw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packusdw(this, left, right, dest)?;
             }
@@ -257,7 +258,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Shuffles `left` using the three low bits of each element of `right`
             // as indices.
             "permd" | "permps" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -277,7 +278,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm256_permute2x128_si256 function.
             // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern.
             "vperm2i128" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 assert_eq!(left.layout.size.bits(), 256);
                 assert_eq!(right.layout.size.bits(), 256);
@@ -314,7 +315,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // in `dest`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8
             "psad.bw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -346,7 +347,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Shuffles bytes from `left` using `right` as pattern.
             // Each 128-bit block is shuffled independently.
             "pshuf.b" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -377,7 +378,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is writen to the corresponding output element.
             // Basically, we multiply `left` with `right.signum()`.
             "psign.b" | "psign.w" | "psign.d" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 psign(this, left, right, dest)?;
             }
@@ -391,7 +392,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is copied to remaining bits.
             "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
             | "psrl.q" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -406,7 +407,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // (except _mm{,256}_srav_epi64, which are not available in AVX2).
             "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256"
             | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left,
diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs
index 8af59df0a68..80b1b2e16e6 100644
--- a/src/tools/miri/src/shims/x86/bmi.rs
+++ b/src/tools/miri/src/shims/x86/bmi.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -34,7 +35,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(EmulateItemResult::NotSupported);
         }
 
-        let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+        let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
         let left = this.read_scalar(left)?;
         let right = this.read_scalar(right)?;
 
diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs
index a91c74283fd..f83ce560c84 100644
--- a/src/tools/miri/src/shims/x86/gfni.rs
+++ b/src/tools/miri/src/shims/x86/gfni.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -30,14 +31,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // See `affine_transform` for details.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_
             "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => {
-                let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 affine_transform(this, left, right, imm8, dest, /* inverse */ false)?;
             }
             // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions.
             // See `affine_transform` for details.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv
             "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => {
-                let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 affine_transform(this, left, right, imm8, dest, /* inverse */ true)?;
             }
             // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions.
@@ -46,7 +47,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
             "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index ac59cc2dfeb..7dee8ddd23c 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,11 +1,11 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, Size};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::helpers::bool_to_simd_element;
 use crate::*;
@@ -46,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     return interp_ok(EmulateItemResult::NotSupported);
                 }
 
-                let [cb_in, a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cb_in, a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let op = if unprefixed_name.starts_with("add") {
                     mir::BinOp::AddWithOverflow
                 } else {
@@ -68,7 +68,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if is_u64 && this.tcx.sess.target.arch != "x86_64" {
                     return interp_ok(EmulateItemResult::NotSupported);
                 }
-                let [c_in, a, b, out] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [c_in, a, b, out] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let out = this.deref_pointer_as(
                     out,
                     if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 },
@@ -85,7 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the instruction behaves like a no-op, so it is always safe to call the
             // intrinsic.
             "sse2.pause" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // Only exhibit the spin-loop hint behavior when SSE2 is enabled.
                 if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
                     this.yield_active_thread();
@@ -104,7 +104,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     len = 8;
                 }
 
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 pclmulqdq(this, left, right, imm, dest, len)?;
             }
diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs
index 23c83553f3b..d37fad3e6c7 100644
--- a/src/tools/miri/src/shims/x86/sha.rs
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -4,9 +4,10 @@
 //!
 //! [RustCrypto's sha256 module]: https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/soft.rs
 
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -52,7 +53,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match unprefixed_name {
             // Used to implement the _mm_sha256rnds2_epu32 function.
             "256rnds2" => {
-                let [a, b, k] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [a, b, k] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (a_reg, a_len) = this.project_to_simd(a)?;
                 let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -73,7 +74,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement the _mm_sha256msg1_epu32 function.
             "256msg1" => {
-                let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (a_reg, a_len) = this.project_to_simd(a)?;
                 let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -91,7 +92,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement the _mm_sha256msg2_epu32 function.
             "256msg2" => {
-                let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (a_reg, a_len) = this.project_to_simd(a)?;
                 let (b_reg, b_len) = this.project_to_simd(b)?;
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index fd7aba2437a..1ec15d609c6 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps,
@@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Performs the operations on the first component of `left` and
             // `right` and copies the remaining components from `left`.
             "min.ss" | "max.ss" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.ss" => FloatBinOp::Min,
@@ -49,7 +50,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.ps" | "max.ps" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.ps" => FloatBinOp::Min,
@@ -63,7 +64,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Performs the operations on the first component of `op` and
             // copies the remaining components from `op`.
             "rcp.ss" | "rsqrt.ss" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "rcp.ss" => FloatUnaryOp::Rcp,
@@ -76,7 +77,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions.
             // Performs the operations on all components of `op`.
             "rcp.ps" | "rsqrt.ps" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "rcp.ps" => FloatUnaryOp::Rcp,
@@ -95,7 +96,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions
             // with hard-coded operations.
             "cmp.ss" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -111,7 +112,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions
             // with hard-coded operations.
             "cmp.ps" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -124,7 +125,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
             | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss"
             | "ucomineq.ss" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -152,7 +153,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cvtss_si64 and _mm_cvttss_si64 functions.
             // Converts the first component of `op` from f32 to i32/i64.
             "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let (op, _) = this.project_to_simd(op)?;
 
                 let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -180,7 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // are copied from `left`.
             // https://www.felixcloutier.com/x86/cvtsi2ss
             "cvtsi2ss" | "cvtsi642ss" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index e0695b7cb7b..d6052f83077 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::Double;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int,
@@ -40,7 +41,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // intermediate signed 32-bit integers. Horizontally add adjacent pairs of
             // intermediate 32-bit integers, and pack the results in `dest`.
             "pmadd.wd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -78,7 +79,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             //
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8
             "psad.bw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -116,7 +117,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is copied to remaining bits.
             "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
             | "psrl.q" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -131,7 +132,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and _mm_cvttpd_epi32 functions.
             // Converts packed f32/f64 to packed i32.
             "cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx);
                 let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx);
@@ -168,7 +169,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit integer vectors to a single 8-bit integer
             // vector with signed saturation.
             "packsswb.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packsswb(this, left, right, dest)?;
             }
@@ -176,7 +177,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit signed integer vectors to a single 8-bit
             // unsigned integer vector with saturation.
             "packuswb.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packuswb(this, left, right, dest)?;
             }
@@ -184,7 +185,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 32-bit integer vectors to a single 16-bit integer
             // vector with signed saturation.
             "packssdw.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packssdw(this, left, right, dest)?;
             }
@@ -194,7 +195,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.sd" | "max.sd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.sd" => FloatBinOp::Min,
@@ -210,7 +211,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.pd" | "max.pd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.pd" => FloatBinOp::Min,
@@ -229,7 +230,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions
             // with hard-coded operations.
             "cmp.sd" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -245,7 +246,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions
             // with hard-coded operations.
             "cmp.pd" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -258,7 +259,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd"
             | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd"
             | "ucomineq.sd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -286,7 +287,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
             // Converts the first component of `op` from f64 to i32/i64.
             "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let (op, _) = this.project_to_simd(op)?;
 
                 let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -312,7 +313,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts the first f64/f32 from `right` to f32/f64 and copies
             // the remaining elements from `left`
             "cvtsd2ss" | "cvtss2sd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, _) = this.project_to_simd(right)?;
diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs
index 60b7764a01e..ebf3cb5c3ee 100644
--- a/src/tools/miri/src/shims/x86/sse3.rs
+++ b/src/tools/miri/src/shims/x86/sse3.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::horizontal_bin_op;
 use crate::*;
@@ -25,7 +26,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Horizontally add/subtract adjacent floating point values
             // in `left` and `right`.
             "hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "hadd.ps" | "hadd.pd" => mir::BinOp::Add,
@@ -41,7 +42,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the data crosses a cache line, but for Miri this is just a regular
             // unaligned read.
             "ldu.dq" => {
-                let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let src_ptr = this.read_pointer(src_ptr)?;
                 let dest = dest.force_mplace(this)?;
 
diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs
index 93d689a3044..6797039cf56 100644
--- a/src/tools/miri/src/shims/x86/sse41.rs
+++ b/src/tools/miri/src/shims/x86/sse41.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked};
 use crate::*;
@@ -27,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // bits `4..=5` if `imm`, and `i`th bit specifies whether element
             // `i` is zeroed.
             "insertps" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -62,7 +63,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Concatenates two 32-bit signed integer vectors and converts
             // the result to a 16-bit unsigned integer vector with saturation.
             "packusdw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packusdw(this, left, right, dest)?;
             }
@@ -72,7 +73,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // products, and conditionally stores the sum in `dest` using the low
             // 4 bits of `imm`.
             "dpps" | "dppd" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 conditional_dot_product(this, left, right, imm, dest)?;
             }
@@ -80,14 +81,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // functions. Rounds the first element of `right` according to `rounding`
             // and copies the remaining elements from `left`.
             "round.ss" => {
-                let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_first::<rustc_apfloat::ieee::Single>(this, left, right, rounding, dest)?;
             }
             // Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps
             // functions. Rounds the elements of `op` according to `rounding`.
             "round.ps" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
             }
@@ -95,14 +96,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // functions. Rounds the first element of `right` according to `rounding`
             // and copies the remaining elements from `left`.
             "round.sd" => {
-                let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_first::<rustc_apfloat::ieee::Double>(this, left, right, rounding, dest)?;
             }
             // Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd
             // functions. Rounds the elements of `op` according to `rounding`.
             "round.pd" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
             }
@@ -110,7 +111,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Find the minimum unsinged 16-bit integer in `op` and
             // returns its value and position.
             "phminposuw" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (op, op_len) = this.project_to_simd(op)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -144,7 +145,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // offsets specified in `imm`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8
             "mpsadbw" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mpsadbw(this, left, right, imm, dest)?;
             }
@@ -153,7 +154,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Tests `(op & mask) == 0`, `(op & mask) == mask` or
             // `(op & mask) != 0 && (op & mask) != mask`
             "ptestz" | "ptestc" | "ptestnzc" => {
-                let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
                 let res = match unprefixed_name {
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 66bff328626..830513f0291 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -1,9 +1,9 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, Size};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -223,7 +223,7 @@ fn deconstruct_args<'tcx>(
     };
 
     if is_explicit {
-        let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?;
+        let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?;
         let imm = ecx.read_scalar(imm)?.to_u8()?;
 
         let default_len = default_len::<u32>(imm);
@@ -236,7 +236,7 @@ fn deconstruct_args<'tcx>(
 
         interp_ok((str1, str2, Some((len1, len2)), imm))
     } else {
-        let [str1, str2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?;
+        let [str1, str2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?;
         let imm = ecx.read_scalar(imm)?.to_u8()?;
 
         let array_layout = array_layout_fn(ecx, imm)?;
@@ -386,7 +386,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // search for a null terminator (see `deconstruct_args` for more details).
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925
             "pcmpistriz128" | "pcmpistris128" => {
-                let [str1, str2, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [str1, str2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let imm = this.read_scalar(imm)?.to_u8()?;
 
                 let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 };
@@ -406,7 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // than 16 for byte-sized operands or 8 for word-sized operands.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047
             "pcmpestriz128" | "pcmpestris128" => {
-                let [_, len1, _, len2, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_, len1, _, len2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 };
                 let len = this.read_scalar(len)?.to_i32()?;
                 let imm = this.read_scalar(imm)?.to_u8()?;
@@ -433,7 +433,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     return interp_ok(EmulateItemResult::NotSupported);
                 }
 
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let left = this.read_scalar(left)?;
                 let right = this.read_scalar(right)?;
 
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index f3e9ac0e5dc..310d6b8f765 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{horizontal_bin_op, int_abs, pmulhrsw, psign};
 use crate::*;
@@ -24,7 +25,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm_abs_epi{8,16,32} functions.
             // Calculates the absolute value of packed 8/16/32-bit integers.
             "pabs.b.128" | "pabs.w.128" | "pabs.d.128" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 int_abs(this, op, dest)?;
             }
@@ -32,7 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Shuffles bytes from `left` using `right` as pattern.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8
             "pshuf.b.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -61,7 +62,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // integer values in `left` and `right`.
             "phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128"
             | "phsub.d.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (which, saturating) = match unprefixed_name {
                     "phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false),
@@ -80,7 +81,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // produces the output at index `i`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16
             "pmadd.ub.sw.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -115,7 +116,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 1 and then taking the bits `1..=16`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16
             "pmul.hr.sw.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 pmulhrsw(this, left, right, dest)?;
             }
@@ -125,7 +126,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is writen to the corresponding output element.
             // Basically, we multiply `left` with `right.signum()`.
             "psign.b.128" | "psign.w.128" | "psign.d.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 psign(this, left, right, dest)?;
             }
diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr
index 59d7b004417..f91d1b5fa63 100644
--- a/tests/ui/abi/sysv64-zst.stderr
+++ b/tests/ui/abi/sysv64-zst.stderr
@@ -59,7 +59,9 @@ error: fn_abi_of(pass_zst) = FnAbi {
            },
            c_variadic: false,
            fixed_count: 1,
-           conv: X86_64SysV,
+           conv: X86(
+               SysV64,
+           ),
            can_unwind: false,
        }
   --> $DIR/sysv64-zst.rs:8:1