about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-11-25 15:07:16 +0000
committerbors <bors@rust-lang.org>2023-11-25 15:07:16 +0000
commitfe3038f263349190f02491d7467198e17ffb0858 (patch)
treea12bfc94de53321dc41dd9c92513530a976b2b97
parent3166210d68fe43161ef64d682dd604cc60e7607f (diff)
parent547598b67ea272ef134c52b779299012f3fc230e (diff)
Auto merge of #118284 - RalfJung:miri, r=RalfJung
Miri subtree update
-rw-r--r--src/tools/miri/.github/workflows/ci.yml4
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs19
-rwxr-xr-xsrc/tools/miri/ci.sh30
-rw-r--r--src/tools/miri/miri-script/src/commands.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/helpers.rs137
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/provenance_gc.rs9
-rw-r--r--src/tools/miri/src/shims/env.rs53
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs5
-rw-r--r--src/tools/miri/src/shims/intrinsics/mod.rs38
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs17
-rw-r--r--src/tools/miri/src/shims/time.rs4
-rw-r--r--src/tools/miri/src/shims/unix/android/foreign_items.rs30
-rw-r--r--src/tools/miri/src/shims/unix/android/mod.rs1
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs15
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs9
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs7
-rw-r--r--src/tools/miri/src/shims/unix/mod.rs1
-rw-r--r--src/tools/miri/src/shims/x86/aesni.rs1
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs166
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs31
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs113
-rw-r--r--src/tools/miri/src/shims/x86/sse3.rs1
-rw-r--r--src/tools/miri/src/shims/x86/sse41.rs3
-rw-r--r--src/tools/miri/src/shims/x86/ssse3.rs1
-rw-r--r--src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs17
-rw-r--r--src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr20
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr4
-rw-r--r--src/tools/miri/tests/fail/shims/intrinsic_target_feature.rs42
-rw-r--r--src/tools/miri/tests/fail/shims/intrinsic_target_feature.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs5
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs1
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-fs.rs43
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-misc.rs52
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs2
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-avx.rs162
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-avx512.rs2
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs2
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse41.rs2
-rw-r--r--src/tools/miri/tests/utils/mod.rs8
64 files changed, 716 insertions, 454 deletions
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 554a12909fc..dec85e9232f 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -35,10 +35,6 @@ jobs:
     steps:
       - uses: actions/checkout@v3
 
-      - name: Set the tag GC interval to 1 on linux
-        if: runner.os == 'Linux'
-        run: echo "MIRIFLAGS=-Zmiri-provenance-gc=1" >> $GITHUB_ENV
-
       # Cache the global cargo directory, but NOT the local `target` directory which
       # we cannot reuse anyway when the nightly changes (and it grows quite large
       # over time).
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index d921741d5de..8ae5b8c3e82 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -2,6 +2,7 @@
 
 use std::env;
 use std::ffi::OsStr;
+use std::fmt::Write;
 use std::path::PathBuf;
 use std::process::{self, Command};
 
@@ -140,12 +141,20 @@ pub fn setup(
     // Do the build.
     if print_sysroot {
         // Be silent.
-    } else if only_setup {
-        // We want to be explicit.
-        eprintln!("Preparing a sysroot for Miri (target: {target})...");
     } else {
-        // We want to be quiet, but still let the user know that something is happening.
-        eprint!("Preparing a sysroot for Miri (target: {target})... ");
+        let mut msg = String::new();
+        write!(msg, "Preparing a sysroot for Miri (target: {target})").unwrap();
+        if verbose > 0 {
+            write!(msg, " in {}", sysroot_dir.display()).unwrap();
+        }
+        write!(msg, "...").unwrap();
+        if only_setup {
+            // We want to be explicit.
+            eprintln!("{msg}");
+        } else {
+            // We want to be quiet, but still let the user know that something is happening.
+            eprint!("{msg} ");
+        }
     }
     SysrootBuilder::new(&sysroot_dir, target)
         .build_mode(BuildMode::Check)
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index 7808c9acf93..6bcc68ebf7c 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -30,16 +30,23 @@ endgroup
 
 # Test
 function run_tests {
-  if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
+  if [ -n "${MIRI_TEST_TARGET:-}" ]; then
     begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
   else
     begingroup "Testing host architecture"
   fi
 
   ## ui test suite
-  ./miri test
-  if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
-    # Host-only tests: running these on all targets is unlikely to catch more problems and would
+  # On the host and on Linux, also stress-test the GC.
+  if [ -z "${MIRI_TEST_TARGET:-}" ] || [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
+    MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test
+  else
+    ./miri test
+  fi
+
+  # Host-only tests
+  if [ -z "${MIRI_TEST_TARGET:-}" ]; then
+    # Running these on all targets is unlikely to catch more problems and would
     # cost a lot of CI time.
 
     # Tests with optimizations (`-O` is what cargo passes, but crank MIR optimizations up all the
@@ -85,10 +92,11 @@ function run_tests {
 }
 
 function run_tests_minimal {
-  if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
+  if [ -n "${MIRI_TEST_TARGET:-}" ]; then
     begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
   else
-    begingroup "Testing MINIMAL host architecture: only testing $@"
+    echo "run_tests_minimal requires MIRI_TEST_TARGET to be set"
+    exit 1
   fi
 
   ./miri test -- "$@"
@@ -99,16 +107,22 @@ function run_tests_minimal {
   endgroup
 }
 
-# host
+## Main Testing Logic ##
+
+# Host target.
 run_tests
 
+# Extra targets.
+# In particular, fully cover all tier 1 targets.
 case $HOST_TARGET in
   x86_64-unknown-linux-gnu)
     MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
-    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc atomic env align
+    # Some targets are only partially supported.
+    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
+    MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
     MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
     MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
     MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index c24035ae086..e4789c696b3 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -286,7 +286,7 @@ impl Command {
                 "This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
             );
             print!(
-                "To avoid that, abort now and set the `--rustc-git` flag to an existing rustc checkout. Proceed? [y/N] "
+                "To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
             );
             std::io::stdout().flush()?;
             let mut answer = String::new();
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 2a19781775b..ecebb8a331b 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-820f06b21f8373060ff7b515715b8440a6a6c197
+3668a8af1b81447c4afa1f82f60d7b94b71a549f
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 965cd534d1e..21f1d684924 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -5,17 +5,18 @@ use std::time::Duration;
 
 use log::trace;
 
+use rustc_apfloat::ieee::{Double, Single};
 use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
 use rustc_middle::ty::{
     self,
-    layout::{IntegerExt as _, LayoutOf, TyAndLayout},
-    IntTy, Ty, TyCtxt, UintTy,
+    layout::{LayoutOf, TyAndLayout},
+    FloatTy, IntTy, Ty, TyCtxt, UintTy,
 };
 use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
-use rustc_target::abi::{Align, FieldIdx, FieldsShape, Integer, Size, Variants};
+use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
 use rustc_target::spec::abi::Abi;
 
 use rand::RngCore;
@@ -565,10 +566,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
     /// if this is not the case.
     fn assert_target_os_is_unix(&self, name: &str) {
-        assert!(
-            target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()),
-            "`{name}` is only available for supported UNIX family targets",
-        );
+        assert!(self.target_os_is_unix(), "`{name}` is only available for unix targets",);
+    }
+
+    fn target_os_is_unix(&self) -> bool {
+        self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
     }
 
     /// Get last error variable as a place, lazily allocating thread-local storage for it if
@@ -985,65 +987,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
-    /// Converts `f` to integer type `dest_ty` after rounding with mode `round`.
+    /// Converts `src` from floating point to integer type `dest_ty`
+    /// after rounding with mode `round`.
     /// Returns `None` if `f` is NaN or out of range.
-    fn float_to_int_checked<F>(
+    fn float_to_int_checked(
         &self,
-        f: F,
+        src: &ImmTy<'tcx, Provenance>,
         cast_to: TyAndLayout<'tcx>,
         round: rustc_apfloat::Round,
-    ) -> Option<ImmTy<'tcx, Provenance>>
-    where
-        F: rustc_apfloat::Float + Into<Scalar<Provenance>>,
-    {
+    ) -> InterpResult<'tcx, Option<ImmTy<'tcx, Provenance>>> {
         let this = self.eval_context_ref();
 
-        let val = match cast_to.ty.kind() {
-            // Unsigned
-            ty::Uint(t) => {
-                let size = Integer::from_uint_ty(this, *t).size();
-                let res = f.to_u128_r(size.bits_usize(), round, &mut false);
-                if res.status.intersects(
-                    rustc_apfloat::Status::INVALID_OP
-                        | rustc_apfloat::Status::OVERFLOW
-                        | rustc_apfloat::Status::UNDERFLOW,
-                ) {
-                    // Floating point value is NaN (flagged with INVALID_OP) or outside the range
-                    // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
-                    return None;
-                } else {
-                    // Floating point value can be represented by the integer type after rounding.
-                    // The INEXACT flag is ignored on purpose to allow rounding.
-                    Scalar::from_uint(res.value, size)
+        fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
+            this: &MiriInterpCx<'_, 'tcx>,
+            src: F,
+            cast_to: TyAndLayout<'tcx>,
+            round: rustc_apfloat::Round,
+        ) -> (Scalar<Provenance>, rustc_apfloat::Status) {
+            let int_size = cast_to.layout.size;
+            match cast_to.ty.kind() {
+                // Unsigned
+                ty::Uint(_) => {
+                    let res = src.to_u128_r(int_size.bits_usize(), round, &mut false);
+                    (Scalar::from_uint(res.value, int_size), res.status)
                 }
-            }
-            // Signed
-            ty::Int(t) => {
-                let size = Integer::from_int_ty(this, *t).size();
-                let res = f.to_i128_r(size.bits_usize(), round, &mut false);
-                if res.status.intersects(
-                    rustc_apfloat::Status::INVALID_OP
-                        | rustc_apfloat::Status::OVERFLOW
-                        | rustc_apfloat::Status::UNDERFLOW,
-                ) {
-                    // Floating point value is NaN (flagged with INVALID_OP) or outside the range
-                    // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
-                    return None;
-                } else {
-                    // Floating point value can be represented by the integer type after rounding.
-                    // The INEXACT flag is ignored on purpose to allow rounding.
-                    Scalar::from_int(res.value, size)
+                // Signed
+                ty::Int(_) => {
+                    let res = src.to_i128_r(int_size.bits_usize(), round, &mut false);
+                    (Scalar::from_int(res.value, int_size), res.status)
                 }
+                // Nothing else
+                _ =>
+                    span_bug!(
+                        this.cur_span(),
+                        "attempted float-to-int conversion with non-int output type {}",
+                        cast_to.ty,
+                    ),
             }
+        }
+
+        let (val, status) = match src.layout.ty.kind() {
+            // f32
+            ty::Float(FloatTy::F32) =>
+                float_to_int_inner::<Single>(this, src.to_scalar().to_f32()?, cast_to, round),
+            // f64
+            ty::Float(FloatTy::F64) =>
+                float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
             // Nothing else
             _ =>
                 span_bug!(
                     this.cur_span(),
-                    "attempted float-to-int conversion with non-int output type {}",
-                    cast_to.ty,
+                    "attempted float-to-int conversion with non-float input type {}",
+                    src.layout.ty,
                 ),
         };
-        Some(ImmTy::from_scalar(val, cast_to))
+
+        if status.intersects(
+            rustc_apfloat::Status::INVALID_OP
+                | rustc_apfloat::Status::OVERFLOW
+                | rustc_apfloat::Status::UNDERFLOW,
+        ) {
+            // Floating point value is NaN (flagged with INVALID_OP) or outside the range
+            // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
+            Ok(None)
+        } else {
+            // Floating point value can be represented by the integer type after rounding.
+            // The INEXACT flag is ignored on purpose to allow rounding.
+            Ok(Some(ImmTy::from_scalar(val, cast_to)))
+        }
     }
 
     /// Returns an integer type that is twice wide as `ty`
@@ -1063,6 +1074,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             _ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
         }
     }
+
+    /// Checks that target feature `target_feature` is enabled.
+    ///
+    /// If not enabled, emits an UB error that states that the feature is
+    /// required by `intrinsic`.
+    fn expect_target_feature_for_intrinsic(
+        &self,
+        intrinsic: Symbol,
+        target_feature: &str,
+    ) -> InterpResult<'tcx, ()> {
+        let this = self.eval_context_ref();
+        if !this.tcx.sess.unstable_target_features.contains(&Symbol::intern(target_feature)) {
+            throw_ub_format!(
+                "attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
+            );
+        }
+        Ok(())
+    }
 }
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@@ -1143,12 +1172,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
     local_crates
 }
 
-/// Helper function used inside the shims of foreign functions to check that
-/// `target_os` is a supported UNIX OS.
-pub fn target_os_is_unix(target_os: &str) -> bool {
-    matches!(target_os, "linux" | "macos" | "freebsd" | "android")
-}
-
 pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> {
     // SIMD uses all-1 as pattern for "true". In two's complement,
     // -1 has all its bits set to one and `from_int` will truncate or
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index d906553ec40..1eb40ab826c 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -125,7 +125,7 @@ pub use crate::machine::{
 };
 pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::operator::EvalContextExt as _;
-pub use crate::provenance_gc::{EvalContextExt as _, VisitProvenance, VisitWith, LiveAllocs};
+pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith};
 pub use crate::range_map::RangeMap;
 
 /// Insert rustc arguments at the beginning of the argument list that Miri wants to be
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index ef6d49f041f..ab178f82d9f 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -157,15 +157,13 @@ pub struct LiveAllocs<'a, 'mir, 'tcx> {
 
 impl LiveAllocs<'_, '_, '_> {
     pub fn is_live(&self, id: AllocId) -> bool {
-        self.collected.contains(&id) ||
-        self.ecx.is_alloc_live(id)
+        self.collected.contains(&id) || self.ecx.is_alloc_live(id)
     }
 }
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
     fn run_provenance_gc(&mut self) {
-
         // We collect all tags from various parts of the interpreter, but also
         let this = self.eval_context_mut();
 
@@ -196,10 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
 
     fn remove_unreachable_allocs(&mut self, allocs: FxHashSet<AllocId>) {
         let this = self.eval_context_mut();
-        let allocs = LiveAllocs {
-            ecx: this,
-            collected: allocs,
-        };
+        let allocs = LiveAllocs { ecx: this, collected: allocs };
         this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
         this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs);
         if let Some(borrow_tracker) = &this.machine.borrow_tracker {
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index 42438985907..9e19f720211 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -9,7 +9,6 @@ use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::Ty;
 use rustc_target::abi::Size;
 
-use crate::helpers::target_os_is_unix;
 use crate::*;
 
 /// Check whether an operation that writes to a target buffer was successful.
@@ -53,16 +52,15 @@ impl<'tcx> EnvVars<'tcx> {
         ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
         config: &MiriConfig,
     ) -> InterpResult<'tcx> {
-        let target_os = ecx.tcx.sess.target.os.as_ref();
-
+        // Initialize the `env_vars` map.
         // Skip the loop entirely if we don't want to forward anything.
         if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() {
             for (name, value) in &config.env {
                 let forward = ecx.machine.communicate()
                     || config.forwarded_env_vars.iter().any(|v| **v == *name);
                 if forward {
-                    let var_ptr = match target_os {
-                        target if target_os_is_unix(target) =>
+                    let var_ptr = match ecx.tcx.sess.target.os.as_ref() {
+                        _ if ecx.target_os_is_unix() =>
                             alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?,
                         "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?,
                         unsupported =>
@@ -75,7 +73,17 @@ impl<'tcx> EnvVars<'tcx> {
                 }
             }
         }
-        ecx.update_environ()
+
+        // Initialize the `environ` pointer when needed.
+        if ecx.target_os_is_unix() {
+            // This is memory backing an extern static, hence `ExternStatic`, not `Env`.
+            let layout = ecx.machine.layouts.mut_raw_ptr;
+            let place = ecx.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
+            ecx.write_null(&place)?;
+            ecx.machine.env_vars.environ = Some(place);
+            ecx.update_environ()?;
+        }
+        Ok(())
     }
 
     pub(crate) fn cleanup<'mir>(
@@ -87,9 +95,11 @@ impl<'tcx> EnvVars<'tcx> {
             ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?;
         }
         // Deallocate environ var list.
-        let environ = ecx.machine.env_vars.environ.as_ref().unwrap();
-        let old_vars_ptr = ecx.read_pointer(environ)?;
-        ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
+        if ecx.target_os_is_unix() {
+            let environ = ecx.machine.env_vars.environ.as_ref().unwrap();
+            let old_vars_ptr = ecx.read_pointer(environ)?;
+            ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
+        }
         Ok(())
     }
 }
@@ -127,6 +137,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let name_ptr = this.read_pointer(name_op)?;
         let name = this.read_os_str_from_c_str(name_ptr)?;
+        this.read_environ()?;
         Ok(match this.machine.env_vars.map.get(name) {
             Some(var_ptr) => {
                 // The offset is used to strip the "{name}=" part of the string.
@@ -275,7 +286,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Delete environment variable `{name}`
             if let Some(var) = this.machine.env_vars.map.remove(&name) {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
-                this.update_environ()?;
             }
             Ok(this.eval_windows("c", "TRUE"))
         } else {
@@ -284,7 +294,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
-            this.update_environ()?;
             Ok(this.eval_windows("c", "TRUE"))
         }
     }
@@ -431,15 +440,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     fn update_environ(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         // Deallocate the old environ list, if any.
-        if let Some(environ) = this.machine.env_vars.environ.as_ref() {
-            let old_vars_ptr = this.read_pointer(environ)?;
+        let environ = this.machine.env_vars.environ.as_ref().unwrap().clone();
+        let old_vars_ptr = this.read_pointer(&environ)?;
+        if !this.ptr_is_null(old_vars_ptr)? {
             this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
-        } else {
-            // No `environ` allocated yet, let's do that.
-            // This is memory backing an extern static, hence `ExternStatic`, not `Env`.
-            let layout = this.machine.layouts.mut_raw_ptr;
-            let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
-            this.machine.env_vars.environ = Some(place);
         }
 
         // Collect all the pointers to each variable in a vector.
@@ -459,8 +463,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             let place = this.project_field(&vars_place, idx)?;
             this.write_pointer(var, &place)?;
         }
-        this.write_pointer(vars_place.ptr(), &this.machine.env_vars.environ.clone().unwrap())?;
+        this.write_pointer(vars_place.ptr(), &environ)?;
+
+        Ok(())
+    }
 
+    /// Reads from the `environ` static.
+    /// We don't actually care about the result, but we care about this potentially causing a data race.
+    fn read_environ(&self) -> InterpResult<'tcx> {
+        let this = self.eval_context_ref();
+        let environ = this.machine.env_vars.environ.as_ref().unwrap();
+        let _vars_ptr = this.read_pointer(environ)?;
         Ok(())
     }
 
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index d7aaa08dbf3..0957e72ee91 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -22,7 +22,6 @@ use rustc_target::{
 };
 
 use super::backtrace::EvalContextExt as _;
-use crate::helpers::target_os_is_unix;
 use crate::*;
 
 /// Type of dynamic symbols (for `dlsym` et al)
@@ -1012,9 +1011,11 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
                 let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
                 let arg = this.read_scalar(arg)?.to_i32()?;
+                // Note that different arguments might have different target feature requirements.
                 match arg {
                     // YIELD
                     1 => {
+                        this.expect_target_feature_for_intrinsic(link_name, "v6")?;
                         this.yield_active_thread();
                     }
                     _ => {
@@ -1058,7 +1059,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             // Platform-specific shims
             _ =>
                 return match this.tcx.sess.target.os.as_ref() {
-                    target_os if target_os_is_unix(target_os) =>
+                    _ if this.target_os_is_unix() =>
                         shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
                             this, link_name, abi, args, dest,
                         ),
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index 8c90ceba1e4..66918db995d 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -365,36 +365,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [val] = check_arg_count(args)?;
                 let val = this.read_immediate(val)?;
 
-                let res = match val.layout.ty.kind() {
-                    ty::Float(FloatTy::F32) => {
-                        let f = val.to_scalar().to_f32()?;
-                        this
-                            .float_to_int_checked(f, dest.layout, Round::TowardZero)
-                            .ok_or_else(|| {
-                                err_ub_format!(
-                                    "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
-                                    dest.layout.ty
-                                )
-                            })?
-                    }
-                    ty::Float(FloatTy::F64) => {
-                        let f = val.to_scalar().to_f64()?;
-                        this
-                            .float_to_int_checked(f, dest.layout, Round::TowardZero)
-                            .ok_or_else(|| {
-                                err_ub_format!(
-                                    "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
-                                    dest.layout.ty
-                                )
-                            })?
-                    }
-                    _ =>
-                        span_bug!(
-                            this.cur_span(),
-                            "`float_to_int_unchecked` called with non-float input type {:?}",
-                            val.layout.ty
-                        ),
-                };
+                let res = this
+                    .float_to_int_checked(&val, dest.layout, Round::TowardZero)?
+                    .ok_or_else(|| {
+                        err_ub_format!(
+                            "`float_to_int_unchecked` intrinsic called on {val} which cannot be represented in target type `{:?}`",
+                            dest.layout.ty
+                        )
+                    })?;
 
                 this.write_immediate(*res, dest)?;
             }
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index 70f90aac2c2..d0a293d5f81 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -447,22 +447,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
                             this.float_to_float_or_int(&op, dest.layout)?,
                         // Float-to-int in unchecked mode
-                        (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
-                            let f = op.to_scalar().to_f32()?;
-                            this.float_to_int_checked(f, dest.layout, Round::TowardZero)
+                        (ty::Float(_), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
+                            this.float_to_int_checked(&op, dest.layout, Round::TowardZero)?
                                 .ok_or_else(|| {
                                     err_ub_format!(
-                                        "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
-                                        dest.layout.ty
-                                    )
-                                })?
-                        }
-                        (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
-                            let f = op.to_scalar().to_f64()?;
-                            this.float_to_int_checked(f, dest.layout, Round::TowardZero)
-                                .ok_or_else(|| {
-                                    err_ub_format!(
-                                        "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
+                                        "`simd_cast` intrinsic called on {op} which cannot be represented in target type `{:?}`",
                                         dest.layout.ty
                                     )
                                 })?
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 792122a0016..13ce9d119bc 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -31,8 +31,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let mut relative_clocks;
 
         match this.tcx.sess.target.os.as_ref() {
-            "linux" => {
-                // Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
+            "linux" | "freebsd" => {
+                // Linux and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the
                 // Unix epoch, including effects which may cause time to move backwards such as NTP.
                 // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
                 // is just specified to be "faster and less precise", so we implement both the same way.
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
deleted file mode 100644
index f61ebd5a3a8..00000000000
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use rustc_span::Symbol;
-use rustc_target::spec::abi::Abi;
-
-use crate::*;
-use shims::foreign_items::EmulateForeignItemResult;
-
-impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
-
-pub fn is_dyn_sym(_name: &str) -> bool {
-    false
-}
-
-pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    #[allow(unused, clippy::match_single_binding)] // there isn't anything here yet
-    fn emulate_foreign_item_inner(
-        &mut self,
-        link_name: Symbol,
-        abi: Abi,
-        args: &[OpTy<'tcx, Provenance>],
-        dest: &PlaceTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, EmulateForeignItemResult> {
-        let this = self.eval_context_mut();
-
-        match link_name.as_str() {
-            _ => return Ok(EmulateForeignItemResult::NotSupported),
-        }
-
-        Ok(EmulateForeignItemResult::NeedsJumping)
-    }
-}
diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs
deleted file mode 100644
index 09c6507b24f..00000000000
--- a/src/tools/miri/src/shims/unix/android/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod foreign_items;
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index d155623eb7b..23342c8045e 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -15,7 +15,6 @@ use shims::unix::mem::EvalContextExt as _;
 use shims::unix::sync::EvalContextExt as _;
 use shims::unix::thread::EvalContextExt as _;
 
-use shims::unix::android::foreign_items as android;
 use shims::unix::freebsd::foreign_items as freebsd;
 use shims::unix::linux::foreign_items as linux;
 use shims::unix::macos::foreign_items as macos;
@@ -32,11 +31,10 @@ fn is_dyn_sym(name: &str, target_os: &str) -> bool {
         // Give specific OSes a chance to allow their symbols.
         _ =>
             match target_os {
-                "android" => android::is_dyn_sym(name),
                 "freebsd" => freebsd::is_dyn_sym(name),
                 "linux" => linux::is_dyn_sym(name),
                 "macos" => macos::is_dyn_sym(name),
-                target_os => panic!("unsupported Unix OS {target_os}"),
+                _ => false,
             },
     }
 }
@@ -163,6 +161,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             "ftruncate64" => {
                 let [fd, length] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let length = this.read_scalar(length)?.to_i64()?;
+                let result = this.ftruncate64(fd, length.into())?;
+                this.write_scalar(result, dest)?;
+            }
+            "ftruncate" => {
+                let [fd, length] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let result = this.ftruncate64(fd, length)?;
                 this.write_scalar(result, dest)?;
             }
@@ -696,7 +704,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             _ => {
                 let target_os = &*this.tcx.sess.target.os;
                 return match target_os {
-                    "android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 471eadb8c35..ba40a1b3c32 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -1504,16 +1504,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
-    fn ftruncate64(
-        &mut self,
-        fd_op: &OpTy<'tcx, Provenance>,
-        length_op: &OpTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, Scalar<Provenance>> {
+    fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar<Provenance>> {
         let this = self.eval_context_mut();
 
-        let fd = this.read_scalar(fd_op)?.to_i32()?;
-        let length = this.read_scalar(length_op)?.to_i64()?;
-
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`ftruncate64`", reject_with)?;
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 e8f35e7ba57..07e19cadd6e 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -72,13 +72,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let result = this.lseek64(fd, offset, whence)?;
                 this.write_scalar(result, dest)?;
             }
-            "ftruncate" => {
-                let [fd, length] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                // macOS is 64bit-only, so this is ftruncate64
-                let result = this.ftruncate64(fd, length)?;
-                this.write_scalar(result, dest)?;
-            }
             "realpath$DARWIN_EXTSN" => {
                 let [path, resolved_path] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs
index 2f801493352..638473da02b 100644
--- a/src/tools/miri/src/shims/unix/mod.rs
+++ b/src/tools/miri/src/shims/unix/mod.rs
@@ -5,7 +5,6 @@ mod mem;
 mod sync;
 mod thread;
 
-mod android;
 mod freebsd;
 mod linux;
 mod macos;
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index aef930595b2..fb0b7015127 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         dest: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx, EmulateForeignItemResult> {
         let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "aes")?;
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.aesni.").unwrap();
 
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index d88a3127ecc..2ae269db412 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir;
+use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
@@ -119,53 +119,32 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
     }
 }
 
-/// Floating point comparison operation
-///
-/// <https://www.felixcloutier.com/x86/cmpss>
-/// <https://www.felixcloutier.com/x86/cmpps>
-/// <https://www.felixcloutier.com/x86/cmpsd>
-/// <https://www.felixcloutier.com/x86/cmppd>
-#[derive(Copy, Clone)]
-enum FloatCmpOp {
-    Eq,
-    Lt,
-    Le,
-    Unord,
-    Neq,
-    /// Not less-than
-    Nlt,
-    /// Not less-or-equal
-    Nle,
-    /// Ordered, i.e. neither of them is NaN
-    Ord,
-}
-
-impl FloatCmpOp {
-    /// Convert from the `imm` argument used to specify the comparison
-    /// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
-    fn from_intrinsic_imm(imm: i8, intrinsic: &str) -> InterpResult<'_, Self> {
-        match imm {
-            0 => Ok(Self::Eq),
-            1 => Ok(Self::Lt),
-            2 => Ok(Self::Le),
-            3 => Ok(Self::Unord),
-            4 => Ok(Self::Neq),
-            5 => Ok(Self::Nlt),
-            6 => Ok(Self::Nle),
-            7 => Ok(Self::Ord),
-            imm => {
-                throw_unsup_format!("invalid `imm` parameter of {intrinsic}: {imm}");
-            }
-        }
-    }
-}
-
 #[derive(Copy, Clone)]
 enum FloatBinOp {
     /// Arithmetic operation
     Arith(mir::BinOp),
     /// Comparison
-    Cmp(FloatCmpOp),
+    ///
+    /// The semantics of this operator is a case distinction: we compare the two operands,
+    /// and then we return one of the four booleans `gt`, `lt`, `eq`, `unord` depending on
+    /// which class they fall into.
+    ///
+    /// AVX supports all 16 combinations, SSE only a subset
+    ///
+    /// <https://www.felixcloutier.com/x86/cmpss>
+    /// <https://www.felixcloutier.com/x86/cmpps>
+    /// <https://www.felixcloutier.com/x86/cmpsd>
+    /// <https://www.felixcloutier.com/x86/cmppd>
+    Cmp {
+        /// Result when lhs < rhs
+        gt: bool,
+        /// Result when lhs > rhs
+        lt: bool,
+        /// Result when lhs == rhs
+        eq: bool,
+        /// Result when lhs is NaN or rhs is NaN
+        unord: bool,
+    },
     /// Minimum value (with SSE semantics)
     ///
     /// <https://www.felixcloutier.com/x86/minss>
@@ -182,6 +161,51 @@ enum FloatBinOp {
     Max,
 }
 
+impl FloatBinOp {
+    /// Convert from the `imm` argument used to specify the comparison
+    /// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
+    fn cmp_from_imm<'tcx>(
+        this: &crate::MiriInterpCx<'_, 'tcx>,
+        imm: i8,
+        intrinsic: Symbol,
+    ) -> InterpResult<'tcx, Self> {
+        // Only bits 0..=4 are used, remaining should be zero.
+        if imm & !0b1_1111 != 0 {
+            throw_unsup_format!("invalid `imm` parameter of {intrinsic}: 0x{imm:x}");
+        }
+        // Bit 4 specifies whether the operation is quiet or signaling, which
+        // we do not care in Miri.
+        // Bits 0..=2 specifies the operation.
+        // `gt` indicates the result to be returned when the LHS is strictly
+        // greater than the RHS, and so on.
+        let (gt, lt, eq, mut unord) = match imm & 0b111 {
+            // Equal
+            0x0 => (false, false, true, false),
+            // Less-than
+            0x1 => (false, true, false, false),
+            // Less-or-equal
+            0x2 => (false, true, true, false),
+            // Unordered (either is NaN)
+            0x3 => (false, false, false, true),
+            // Not equal
+            0x4 => (true, true, false, true),
+            // Not less-than
+            0x5 => (true, false, true, true),
+            // Not less-or-equal
+            0x6 => (true, false, false, true),
+            // Ordered (neither is NaN)
+            0x7 => (true, true, true, false),
+            _ => unreachable!(),
+        };
+        // When bit 3 is 1 (only possible in AVX), unord is toggled.
+        if imm & 0b1000 != 0 {
+            this.expect_target_feature_for_intrinsic(intrinsic, "avx")?;
+            unord = !unord;
+        }
+        Ok(Self::Cmp { gt, lt, eq, unord })
+    }
+}
+
 /// Performs `which` scalar operation on `left` and `right` and returns
 /// the result.
 fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
@@ -195,20 +219,15 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
             let res = this.wrapping_binary_op(which, left, right)?;
             Ok(res.to_scalar())
         }
-        FloatBinOp::Cmp(which) => {
+        FloatBinOp::Cmp { gt, lt, eq, unord } => {
             let left = left.to_scalar().to_float::<F>()?;
             let right = right.to_scalar().to_float::<F>()?;
-            // FIXME: Make sure that these operations match the semantics
-            // of cmpps/cmpss/cmppd/cmpsd
-            let res = match which {
-                FloatCmpOp::Eq => left == right,
-                FloatCmpOp::Lt => left < right,
-                FloatCmpOp::Le => left <= right,
-                FloatCmpOp::Unord => left.is_nan() || right.is_nan(),
-                FloatCmpOp::Neq => left != right,
-                FloatCmpOp::Nlt => !(left < right),
-                FloatCmpOp::Nle => !(left <= right),
-                FloatCmpOp::Ord => !left.is_nan() && !right.is_nan(),
+
+            let res = match left.partial_cmp(&right) {
+                None => unord,
+                Some(std::cmp::Ordering::Less) => lt,
+                Some(std::cmp::Ordering::Equal) => eq,
+                Some(std::cmp::Ordering::Greater) => gt,
             };
             Ok(bool_to_simd_element(res, Size::from_bits(F::BITS)))
         }
@@ -312,6 +331,43 @@ fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>(
     Ok(())
 }
 
+/// Converts each element of `op` from floating point to signed integer.
+///
+/// When the input value is NaN or out of range, fall back to minimum value.
+///
+/// If `op` has more elements than `dest`, extra elements are ignored. If `op`
+/// has less elements than `dest`, the rest is filled with zeros.
+fn convert_float_to_int<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    op: &OpTy<'tcx, Provenance>,
+    rnd: rustc_apfloat::Round,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (op, op_len) = this.operand_to_simd(op)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    // Output must be *signed* integers.
+    assert!(matches!(dest.layout.field(this, 0).ty.kind(), ty::Int(_)));
+
+    for i in 0..op_len.min(dest_len) {
+        let op = this.read_immediate(&this.project_index(&op, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
+            // Fallback to minimum acording to SSE/AVX semantics.
+            ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
+        });
+        this.write_immediate(*res, &dest)?;
+    }
+    // Fill remainder with zeros
+    for i in op_len..dest_len {
+        let dest = this.project_index(&dest, i)?;
+        this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
+    }
+
+    Ok(())
+}
+
 /// Horizontaly performs `which` operation on adjacent values of
 /// `left` and `right` SIMD vectors and stores the result in `dest`.
 fn horizontal_bin_op<'tcx>(
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index 831228b7a26..6e06f62b34c 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi;
 
 use rand::Rng as _;
 
-use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
+use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp};
 use crate::*;
 use shims::foreign_items::EmulateForeignItemResult;
 
@@ -21,6 +21,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         dest: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx, EmulateForeignItemResult> {
         let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "sse")?;
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap();
         // All these intrinsics operate on 128-bit (f32x4) SIMD vectors unless stated otherwise.
@@ -95,33 +96,37 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
 
                 unary_op_ps(this, which, op, dest)?;
             }
-            // Used to implement the _mm_cmp_ss function.
+            // Used to implement the _mm_cmp*_ss functions.
             // Performs a comparison operation on the first component of `left`
             // and `right`, returning 0 if false or `u32::MAX` if true. The remaining
             // components are copied from `left`.
+            // _mm_cmp_ss is actually an AVX function where the operation is specified
+            // by a const parameter.
+            // _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, Abi::C { unwind: false }, link_name, args)?;
 
-                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
-                    this.read_scalar(imm)?.to_i8()?,
-                    "llvm.x86.sse.cmp.ss",
-                )?);
+                let which =
+                    FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
 
                 bin_op_simd_float_first::<Single>(this, which, left, right, dest)?;
             }
-            // Used to implement the _mm_cmp_ps function.
+            // Used to implement the _mm_cmp*_ps functions.
             // Performs a comparison operation on each component of `left`
             // and `right`. For each component, returns 0 if false or u32::MAX
             // if true.
+            // _mm_cmp_ps is actually an AVX function where the operation is specified
+            // by a const parameter.
+            // _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, Abi::C { unwind: false }, link_name, args)?;
 
-                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
-                    this.read_scalar(imm)?.to_i8()?,
-                    "llvm.x86.sse.cmp.ps",
-                )?);
+                let which =
+                    FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
 
                 bin_op_simd_float_all::<Single>(this, which, left, right, dest)?;
             }
@@ -163,7 +168,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                 let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let (op, _) = this.operand_to_simd(op)?;
 
-                let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f32()?;
+                let op = this.read_immediate(&this.project_index(&op, 0)?)?;
 
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
@@ -175,7 +180,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     _ => unreachable!(),
                 };
 
-                let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
+                let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
                     // Fallback to minimum acording to SSE semantics.
                     ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
                 });
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 3f2b9f5f0ad..49bf7547ab0 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
-use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
+use super::{bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, FloatBinOp};
 use crate::*;
 use shims::foreign_items::EmulateForeignItemResult;
 
@@ -20,6 +20,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         dest: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx, EmulateForeignItemResult> {
         let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "sse2")?;
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse2.").unwrap();
 
@@ -259,37 +260,42 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     this.write_scalar(Scalar::from_u64(res), &dest)?;
                 }
             }
-            // Used to implement the _mm_cvtps_epi32 and _mm_cvttps_epi32 functions.
-            // Converts packed f32 to packed i32.
-            "cvtps2dq" | "cvttps2dq" => {
+            // Used to implement the _mm_cvtps_epi32, _mm_cvttps_epi32, _mm_cvtpd_epi32
+            // and _mm_cvttpd_epi32 functions.
+            // Converts packed f32/f64 to packed i32.
+            "cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => {
                 let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                let (op, op_len) = this.operand_to_simd(op)?;
-                let (dest, dest_len) = this.place_to_simd(dest)?;
-
-                assert_eq!(dest_len, op_len);
+                let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx);
+                let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx);
+                match unprefixed_name {
+                    "cvtps2dq" | "cvttps2dq" => {
+                        // f32x4 to i32x4 conversion
+                        assert_eq!(op_len, 4);
+                        assert_eq!(dest_len, op_len);
+                    }
+                    "cvtpd2dq" | "cvttpd2dq" => {
+                        // f64x2 to i32x4 conversion
+                        // the last two values are filled with zeros
+                        assert_eq!(op_len, 2);
+                        assert_eq!(dest_len, 4);
+                    }
+                    _ => unreachable!(),
+                }
 
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
                     // https://www.felixcloutier.com/x86/cvtps2dq
-                    "cvtps2dq" => rustc_apfloat::Round::NearestTiesToEven,
+                    // https://www.felixcloutier.com/x86/cvtpd2dq
+                    "cvtps2dq" | "cvtpd2dq" => rustc_apfloat::Round::NearestTiesToEven,
                     // always truncate
                     // https://www.felixcloutier.com/x86/cvttps2dq
-                    "cvttps2dq" => rustc_apfloat::Round::TowardZero,
+                    // https://www.felixcloutier.com/x86/cvttpd2dq
+                    "cvttps2dq" | "cvttpd2dq" => rustc_apfloat::Round::TowardZero,
                     _ => unreachable!(),
                 };
 
-                for i in 0..dest_len {
-                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f32()?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    let res =
-                        this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
-                            // Fallback to minimum acording to SSE2 semantics.
-                            ImmTy::from_int(i32::MIN, this.machine.layouts.i32)
-                        });
-                    this.write_immediate(*res, &dest)?;
-                }
+                convert_float_to_int(this, op, rnd, dest)?;
             }
             // Used to implement the _mm_packs_epi16 function.
             // Converts two 16-bit integer vectors to a single 8-bit integer
@@ -461,18 +467,20 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     this.write_scalar(res, &dest)?;
                 }
             }
-            // Used to implement the _mm_cmp*_sd function.
+            // Used to implement the _mm_cmp*_sd functions.
             // Performs a comparison operation on the first component of `left`
             // and `right`, returning 0 if false or `u64::MAX` if true. The remaining
             // components are copied from `left`.
+            // _mm_cmp_sd is actually an AVX function where the operation is specified
+            // by a const parameter.
+            // _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, Abi::C { unwind: false }, link_name, args)?;
 
-                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
-                    this.read_scalar(imm)?.to_i8()?,
-                    "llvm.x86.sse2.cmp.sd",
-                )?);
+                let which =
+                    FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
 
                 bin_op_simd_float_first::<Double>(this, which, left, right, dest)?;
             }
@@ -480,14 +488,16 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
             // Performs a comparison operation on each component of `left`
             // and `right`. For each component, returns 0 if false or `u64::MAX`
             // if true.
+            // _mm_cmp_pd is actually an AVX function where the operation is specified
+            // by a const parameter.
+            // _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, Abi::C { unwind: false }, link_name, args)?;
 
-                let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
-                    this.read_scalar(imm)?.to_i8()?,
-                    "llvm.x86.sse2.cmp.pd",
-                )?);
+                let which =
+                    FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
 
                 bin_op_simd_float_all::<Double>(this, which, left, right, dest)?;
             }
@@ -522,45 +532,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                 };
                 this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?;
             }
-            // Used to implement the _mm_cvtpd_epi32 and _mm_cvttpd_epi32 functions.
-            // Converts packed f64 to packed i32.
-            "cvtpd2dq" | "cvttpd2dq" => {
-                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (op, op_len) = this.operand_to_simd(op)?;
-                let (dest, dest_len) = this.place_to_simd(dest)?;
-
-                // op is f64x2, dest is i32x4
-                assert_eq!(op_len, 2);
-                assert_eq!(dest_len, 4);
-
-                let rnd = match unprefixed_name {
-                    // "current SSE rounding mode", assume nearest
-                    // https://www.felixcloutier.com/x86/cvtpd2dq
-                    "cvtpd2dq" => rustc_apfloat::Round::NearestTiesToEven,
-                    // always truncate
-                    // https://www.felixcloutier.com/x86/cvttpd2dq
-                    "cvttpd2dq" => rustc_apfloat::Round::TowardZero,
-                    _ => unreachable!(),
-                };
-
-                for i in 0..op_len {
-                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f64()?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    let res =
-                        this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
-                            // Fallback to minimum acording to SSE2 semantics.
-                            ImmTy::from_int(i32::MIN, this.machine.layouts.i32)
-                        });
-                    this.write_immediate(*res, &dest)?;
-                }
-                // Fill the remaining with zeros
-                for i in op_len..dest_len {
-                    let dest = this.project_index(&dest, i)?;
-                    this.write_scalar(Scalar::from_i32(0), &dest)?;
-                }
-            }
             // Use to implement the _mm_cvtsd_si32, _mm_cvttsd_si32,
             // _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
             // Converts the first component of `op` from f64 to i32/i64.
@@ -568,7 +539,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                 let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let (op, _) = this.operand_to_simd(op)?;
 
-                let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f64()?;
+                let op = this.read_immediate(&this.project_index(&op, 0)?)?;
 
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
@@ -580,7 +551,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     _ => unreachable!(),
                 };
 
-                let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
+                let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
                     // Fallback to minimum acording to SSE semantics.
                     ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
                 });
diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs
index 270da36f0e3..99a7a4f2f88 100644
--- a/src/tools/miri/src/shims/x86/sse3.rs
+++ b/src/tools/miri/src/shims/x86/sse3.rs
@@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         dest: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx, EmulateForeignItemResult> {
         let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "sse3")?;
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse3.").unwrap();
 
diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs
index 523f3bfc26f..b3d1056ab06 100644
--- a/src/tools/miri/src/shims/x86/sse41.rs
+++ b/src/tools/miri/src/shims/x86/sse41.rs
@@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         dest: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx, EmulateForeignItemResult> {
         let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "sse4.1")?;
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse41.").unwrap();
 
@@ -199,7 +200,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     Scalar::from_u16(min_index.try_into().unwrap()),
                     &this.project_index(&dest, 1)?,
                 )?;
-                // Fill remaining with zeros
+                // Fill remainder with zeros
                 for i in 2..dest_len {
                     this.write_scalar(Scalar::from_u16(0), &this.project_index(&dest, i)?)?;
                 }
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index dbc2b947b33..724150fd2fe 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
         dest: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx, EmulateForeignItemResult> {
         let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "ssse3")?;
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.ssse3.").unwrap();
 
diff --git a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs
new file mode 100644
index 00000000000..2b9e7a34d65
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs
@@ -0,0 +1,17 @@
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
+//@ignore-target-windows: No libc on Windows
+
+use std::env;
+use std::thread;
+
+fn main() {
+    let t = thread::spawn(|| unsafe {
+        // Access the environment in another thread without taking the env lock.
+        // This represents some C code that queries the environment.
+        libc::getenv(b"TZ\0".as_ptr().cast()); //~ERROR: Data race detected
+    });
+    // Meanwhile, the main thread uses the "safe" Rust env accessor.
+    env::set_var("MY_RUST_VAR", "Ferris");
+
+    t.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr
new file mode 100644
index 00000000000..b81e8db9e0c
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here
+  --> $DIR/env-set_var-data-race.rs:LL:CC
+   |
+LL |         libc::getenv(b"TZ/0".as_ptr().cast());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> $DIR/env-set_var-data-race.rs:LL:CC
+   |
+LL |     env::set_var("MY_RUST_VAR", "Ferris");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at $DIR/env-set_var-data-race.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr
index 560771bc24f..2de8f3420b7 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_32_inf1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, i32>(f32::INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr
index ae78af3dcbd..53ed208bdee 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_32_infneg1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, i32>(f32::NEG_INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr
index 2db3efeaac1..afda7124c11 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_32_nan.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, u32>(f32::NAN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr
index 769c35255bb..8ba46de8641 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_32_nanneg.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, u32>(-f32::NAN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr
index 55df31dddd8..9f4b2af2167 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1f32 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_32_neg.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, u32>(-1.000000001f32);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1f32 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr
index 7a87de7b3b3..a8e56ddb59b 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9f32 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_32_too_big1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, i32>(2147483648.0f32);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr
index 6be9b4924b0..a966e2e639c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9f32 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_32_too_big2.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, u32>((u32::MAX - 127) as f32);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9f32 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr
index 5a467f39d92..6115b381ebe 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9f32 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_32_too_small1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, i32>(-2147483904.0f32);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr
index 5cbf1912139..5db9fb1417c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_inf1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(f64::INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr
index 4a4d71f53ed..3e8dadb79e4 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_infneg1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(f64::NEG_INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr
index 1f970b3985c..cb59974bf45 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128`
   --> $DIR/float_to_int_64_infneg2.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i128>(f64::NEG_INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr
index 85e9aa87a9b..68697060515 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_64_nan.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u32>(f64::NAN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr
index a8f495f7048..505a6463cd3 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.0000000000000999 which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.0000000000000999f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_neg.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(-1.0000000000001f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.0000000000000999 which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.0000000000000999f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr
index 3da8bdf9238..bcfd394686b 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648f64 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_64_too_big1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i32>(2147483648.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648f64 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr
index 57383892c3d..ac6139d7e7d 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18f64 which cannot be represented in target type `i64`
   --> $DIR/float_to_int_64_too_big2.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i64>(9223372036854775808.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18f64 which cannot be represented in target type `i64`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr
index 7558fafd973..e289b4c0fc0 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19f64 which cannot be represented in target type `u64`
   --> $DIR/float_to_int_64_too_big3.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u64>(18446744073709551616.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19f64 which cannot be represented in target type `u64`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr
index d01c19b7391..657c72daa6f 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_too_big4.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(u128::MAX as f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr
index 0af13b8bbf3..2a61b5fe15f 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38f64 which cannot be represented in target type `i128`
   --> $DIR/float_to_int_64_too_big5.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i128>(240282366920938463463374607431768211455.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38f64 which cannot be represented in target type `i128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr
index a99bbe15825..1b4b76ced18 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_too_big6.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(f64::MAX);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr
index cef4acee688..47df8d90c06 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308f64 which cannot be represented in target type `i128`
   --> $DIR/float_to_int_64_too_big7.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i128>(f64::MIN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308f64 which cannot be represented in target type `i128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr
index 0823e84aaf9..c5eb405ee95 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649f64 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_64_too_small1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i32>(-2147483649.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649f64 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr
index 3260faab780..e7d12a18a2a 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18f64 which cannot be represented in target type `i64`
   --> $DIR/float_to_int_64_too_small2.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i64>(-9223372036854777856.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18f64 which cannot be represented in target type `i64`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr
index 4f64fabc331..3d8366c725b 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38f64 which cannot be represented in target type `i128`
   --> $DIR/float_to_int_64_too_small3.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i128>(-240282366920938463463374607431768211455.0f64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38f64 which cannot be represented in target type `i128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr b/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr
index d4d1830e963..d75fefe1ded 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `simd_cast` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32`
+error: Undefined Behavior: `simd_cast` intrinsic called on 3.40282347E+38f32 which cannot be represented in target type `i32`
   --> $DIR/simd-float-to-int.rs:LL:CC
    |
 LL |         let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked();
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_cast` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_cast` intrinsic called on 3.40282347E+38f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/shims/intrinsic_target_feature.rs b/src/tools/miri/tests/fail/shims/intrinsic_target_feature.rs
new file mode 100644
index 00000000000..9263ad381d1
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/intrinsic_target_feature.rs
@@ -0,0 +1,42 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// We cannot use `cfg`-based tricks here since the output would be
+// different for non-x86 targets.
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+// Explicitly disable SSE4.1 because it is enabled by default on macOS
+//@compile-flags: -C target-feature=-sse4.1
+
+#![feature(link_llvm_intrinsics, simd_ffi)]
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+fn main() {
+    assert!(is_x86_feature_detected!("sse"));
+    assert!(!is_x86_feature_detected!("sse4.1"));
+
+    unsafe {
+        // Pass, since SSE is enabled
+        addss(_mm_setzero_ps(), _mm_setzero_ps());
+
+        // Fail, since SSE4.1 is not enabled
+        dpps(_mm_setzero_ps(), _mm_setzero_ps(), 0);
+        //~^ ERROR: Undefined Behavior: attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1
+    }
+}
+
+#[allow(improper_ctypes)]
+extern "C" {
+    #[link_name = "llvm.x86.sse.add.ss"]
+    fn addss(a: __m128, b: __m128) -> __m128;
+
+    #[link_name = "llvm.x86.sse41.dpps"]
+    fn dpps(a: __m128, b: __m128, imm8: u8) -> __m128;
+}
diff --git a/src/tools/miri/tests/fail/shims/intrinsic_target_feature.stderr b/src/tools/miri/tests/fail/shims/intrinsic_target_feature.stderr
new file mode 100644
index 00000000000..8e83d20854f
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/intrinsic_target_feature.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1
+  --> $DIR/intrinsic_target_feature.rs:LL:CC
+   |
+LL |         dpps(_mm_setzero_ps(), _mm_setzero_ps(), 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/intrinsic_target_feature.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs
index d36ffe70321..5c29a1b15a7 100644
--- a/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs
+++ b/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs
@@ -2,15 +2,13 @@
 //@ignore-target-windows: No libc on Windows
 
 use std::ffi::CStr;
-use std::ffi::CString;
 use std::thread;
 
 fn main() {
     unsafe {
         thread::spawn(|| {
             // Access the environment in another thread without taking the env lock
-            let k = CString::new("MIRI_ENV_VAR_TEST".as_bytes()).unwrap();
-            let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+            let s = libc::getenv("MIRI_ENV_VAR_TEST\0".as_ptr().cast());
             if s.is_null() {
                 panic!("null");
             }
@@ -19,5 +17,6 @@ fn main() {
         thread::yield_now();
         // After the main thread exits, env vars will be cleaned up -- but because we have not *joined*
         // the other thread, those accesses technically race with those in the other thread.
+        // We don't want to emit an error here, though.
     }
 }
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
index 5185db0b0e2..adfece58661 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
@@ -1,4 +1,5 @@
 //@ignore-target-windows: no libc on Windows
+//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0`
 //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
 //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
 
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
index 767a4fdbede..697970a0885 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
@@ -23,6 +23,7 @@ fn main() {
     test_file_open_unix_extra_third_arg();
     #[cfg(target_os = "linux")]
     test_o_tmpfile_flag();
+    test_posix_mkstemp();
 }
 
 /// Prepare: compute filename and make sure the file does not exist.
@@ -151,3 +152,45 @@ fn test_o_tmpfile_flag() {
             .raw_os_error(),
     );
 }
+
+fn test_posix_mkstemp() {
+    use std::ffi::OsStr;
+    use std::os::unix::io::FromRawFd;
+    use std::path::Path;
+
+    let valid_template = "fooXXXXXX";
+    // C needs to own this as `mkstemp(3)` says:
+    // "Since it will be modified, `template` must not be a string constant, but
+    // should be declared as a character array."
+    // There seems to be no `as_mut_ptr` on `CString` so we need to use `into_raw`.
+    let ptr = CString::new(valid_template).unwrap().into_raw();
+    let fd = unsafe { libc::mkstemp(ptr) };
+    // Take ownership back in Rust to not leak memory.
+    let slice = unsafe { CString::from_raw(ptr) };
+    assert!(fd > 0);
+    let osstr = OsStr::from_bytes(slice.to_bytes());
+    let path: &Path = osstr.as_ref();
+    let name = path.file_name().unwrap().to_string_lossy();
+    assert!(name.ne("fooXXXXXX"));
+    assert!(name.starts_with("foo"));
+    assert_eq!(name.len(), 9);
+    assert_eq!(
+        name.chars().skip(3).filter(char::is_ascii_alphanumeric).collect::<Vec<char>>().len(),
+        6
+    );
+    let file = unsafe { File::from_raw_fd(fd) };
+    assert!(file.set_len(0).is_ok());
+
+    let invalid_templates = vec!["foo", "barXX", "XXXXXXbaz", "whatXXXXXXever", "X"];
+    for t in invalid_templates {
+        let ptr = CString::new(t).unwrap().into_raw();
+        let fd = unsafe { libc::mkstemp(ptr) };
+        let _ = unsafe { CString::from_raw(ptr) };
+        // "On error, -1 is returned, and errno is set to
+        // indicate the error"
+        assert_eq!(fd, -1);
+        let e = std::io::Error::last_os_error();
+        assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
+        assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput);
+    }
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
index de1acb13cbe..abb384b0a85 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
@@ -172,14 +172,13 @@ fn test_thread_local_errno() {
 }
 
 /// Tests whether clock support exists at all
-#[cfg(not(target_os = "freebsd"))]
 fn test_clocks() {
     let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit();
     let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
     assert_eq!(is_error, 0);
     let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
     assert_eq!(is_error, 0);
-    #[cfg(target_os = "linux")]
+    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
     {
         let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) };
         assert_eq!(is_error, 0);
@@ -238,51 +237,6 @@ fn test_isatty() {
     }
 }
 
-#[cfg(not(target_os = "freebsd"))]
-fn test_posix_mkstemp() {
-    use std::ffi::CString;
-    use std::ffi::OsStr;
-    use std::os::unix::ffi::OsStrExt;
-    use std::os::unix::io::FromRawFd;
-    use std::path::Path;
-
-    let valid_template = "fooXXXXXX";
-    // C needs to own this as `mkstemp(3)` says:
-    // "Since it will be modified, `template` must not be a string constant, but
-    // should be declared as a character array."
-    // There seems to be no `as_mut_ptr` on `CString` so we need to use `into_raw`.
-    let ptr = CString::new(valid_template).unwrap().into_raw();
-    let fd = unsafe { libc::mkstemp(ptr) };
-    // Take ownership back in Rust to not leak memory.
-    let slice = unsafe { CString::from_raw(ptr) };
-    assert!(fd > 0);
-    let osstr = OsStr::from_bytes(slice.to_bytes());
-    let path: &Path = osstr.as_ref();
-    let name = path.file_name().unwrap().to_string_lossy();
-    assert!(name.ne("fooXXXXXX"));
-    assert!(name.starts_with("foo"));
-    assert_eq!(name.len(), 9);
-    assert_eq!(
-        name.chars().skip(3).filter(char::is_ascii_alphanumeric).collect::<Vec<char>>().len(),
-        6
-    );
-    let file = unsafe { File::from_raw_fd(fd) };
-    assert!(file.set_len(0).is_ok());
-
-    let invalid_templates = vec!["foo", "barXX", "XXXXXXbaz", "whatXXXXXXever", "X"];
-    for t in invalid_templates {
-        let ptr = CString::new(t).unwrap().into_raw();
-        let fd = unsafe { libc::mkstemp(ptr) };
-        let _ = unsafe { CString::from_raw(ptr) };
-        // "On error, -1 is returned, and errno is set to
-        // indicate the error"
-        assert_eq!(fd, -1);
-        let e = std::io::Error::last_os_error();
-        assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
-        assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput);
-    }
-}
-
 fn test_memcpy() {
     unsafe {
         let src = [1i8, 2, 3];
@@ -406,9 +360,6 @@ fn test_reallocarray() {
 fn main() {
     test_posix_gettimeofday();
 
-    #[cfg(not(target_os = "freebsd"))] // FIXME we should support this on FreeBSD as well
-    test_posix_mkstemp();
-
     test_posix_realpath_alloc();
     test_posix_realpath_noalloc();
     test_posix_realpath_errors();
@@ -417,7 +368,6 @@ fn main() {
 
     test_isatty();
 
-    #[cfg(not(target_os = "freebsd"))] // FIXME we should support this on FreeBSD as well
     test_clocks();
 
     test_dlsym();
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs
index 090b1db0af0..55d1bacdf45 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-aes-vaes.rs
@@ -1,5 +1,5 @@
 // Ignore everything except x86 and x86_64
-// Any additional target are added to CI should be ignored here
+// Any new targets that are added to CI should be ignored here.
 // (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
 //@ignore-target-aarch64
 //@ignore-target-arm
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/intrinsics-x86-avx.rs
new file mode 100644
index 00000000000..933e3d4153a
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics-x86-avx.rs
@@ -0,0 +1,162 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=+avx
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+use std::mem::transmute;
+
+fn main() {
+    assert!(is_x86_feature_detected!("avx"));
+
+    unsafe {
+        test_avx();
+    }
+}
+
+#[target_feature(enable = "avx")]
+unsafe fn test_avx() {
+    fn expected_cmp<F: PartialOrd>(imm: i32, lhs: F, rhs: F, if_t: F, if_f: F) -> F {
+        let res = match imm {
+            _CMP_EQ_OQ => lhs == rhs,
+            _CMP_LT_OS => lhs < rhs,
+            _CMP_LE_OS => lhs <= rhs,
+            _CMP_UNORD_Q => lhs.partial_cmp(&rhs).is_none(),
+            _CMP_NEQ_UQ => lhs != rhs,
+            _CMP_NLT_UQ => !(lhs < rhs),
+            _CMP_NLE_UQ => !(lhs <= rhs),
+            _CMP_ORD_Q => lhs.partial_cmp(&rhs).is_some(),
+            _CMP_EQ_UQ => lhs == rhs || lhs.partial_cmp(&rhs).is_none(),
+            _CMP_NGE_US => !(lhs >= rhs),
+            _CMP_NGT_US => !(lhs > rhs),
+            _CMP_FALSE_OQ => false,
+            _CMP_NEQ_OQ => lhs != rhs && lhs.partial_cmp(&rhs).is_some(),
+            _CMP_GE_OS => lhs >= rhs,
+            _CMP_GT_OS => lhs > rhs,
+            _CMP_TRUE_US => true,
+            _ => unreachable!(),
+        };
+        if res { if_t } else { if_f }
+    }
+    fn expected_cmp_f32(imm: i32, lhs: f32, rhs: f32) -> f32 {
+        expected_cmp(imm, lhs, rhs, f32::from_bits(u32::MAX), 0.0)
+    }
+    fn expected_cmp_f64(imm: i32, lhs: f64, rhs: f64) -> f64 {
+        expected_cmp(imm, lhs, rhs, f64::from_bits(u64::MAX), 0.0)
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn test_mm_cmp_ss<const IMM: i32>() {
+        let values = [
+            (1.0, 1.0),
+            (0.0, 1.0),
+            (1.0, 0.0),
+            (f32::NAN, 0.0),
+            (0.0, f32::NAN),
+            (f32::NAN, f32::NAN),
+        ];
+
+        for (lhs, rhs) in values {
+            let a = _mm_setr_ps(lhs, 2.0, 3.0, 4.0);
+            let b = _mm_setr_ps(rhs, 5.0, 6.0, 7.0);
+            let r: [u32; 4] = transmute(_mm_cmp_ss::<IMM>(a, b));
+            let e: [u32; 4] =
+                transmute(_mm_setr_ps(expected_cmp_f32(IMM, lhs, rhs), 2.0, 3.0, 4.0));
+            assert_eq!(r, e);
+        }
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn test_mm_cmp_ps<const IMM: i32>() {
+        let values = [
+            (1.0, 1.0),
+            (0.0, 1.0),
+            (1.0, 0.0),
+            (f32::NAN, 0.0),
+            (0.0, f32::NAN),
+            (f32::NAN, f32::NAN),
+        ];
+
+        for (lhs, rhs) in values {
+            let a = _mm_set1_ps(lhs);
+            let b = _mm_set1_ps(rhs);
+            let r: [u32; 4] = transmute(_mm_cmp_ps::<IMM>(a, b));
+            let e: [u32; 4] = transmute(_mm_set1_ps(expected_cmp_f32(IMM, lhs, rhs)));
+            assert_eq!(r, e);
+        }
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn test_mm_cmp_sd<const IMM: i32>() {
+        let values = [
+            (1.0, 1.0),
+            (0.0, 1.0),
+            (1.0, 0.0),
+            (f64::NAN, 0.0),
+            (0.0, f64::NAN),
+            (f64::NAN, f64::NAN),
+        ];
+
+        for (lhs, rhs) in values {
+            let a = _mm_setr_pd(lhs, 2.0);
+            let b = _mm_setr_pd(rhs, 3.0);
+            let r: [u64; 2] = transmute(_mm_cmp_sd::<IMM>(a, b));
+            let e: [u64; 2] = transmute(_mm_setr_pd(expected_cmp_f64(IMM, lhs, rhs), 2.0));
+            assert_eq!(r, e);
+        }
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn test_mm_cmp_pd<const IMM: i32>() {
+        let values = [
+            (1.0, 1.0),
+            (0.0, 1.0),
+            (1.0, 0.0),
+            (f64::NAN, 0.0),
+            (0.0, f64::NAN),
+            (f64::NAN, f64::NAN),
+        ];
+
+        for (lhs, rhs) in values {
+            let a = _mm_set1_pd(lhs);
+            let b = _mm_set1_pd(rhs);
+            let r: [u64; 2] = transmute(_mm_cmp_pd::<IMM>(a, b));
+            let e: [u64; 2] = transmute(_mm_set1_pd(expected_cmp_f64(IMM, lhs, rhs)));
+            assert_eq!(r, e);
+        }
+    }
+
+    #[target_feature(enable = "avx")]
+    unsafe fn test_cmp<const IMM: i32>() {
+        test_mm_cmp_ss::<IMM>();
+        test_mm_cmp_ps::<IMM>();
+        test_mm_cmp_sd::<IMM>();
+        test_mm_cmp_pd::<IMM>();
+    }
+
+    test_cmp::<_CMP_EQ_OQ>();
+    test_cmp::<_CMP_LT_OS>();
+    test_cmp::<_CMP_LE_OS>();
+    test_cmp::<_CMP_UNORD_Q>();
+    test_cmp::<_CMP_NEQ_UQ>();
+    test_cmp::<_CMP_NLT_UQ>();
+    test_cmp::<_CMP_NLE_UQ>();
+    test_cmp::<_CMP_ORD_Q>();
+    test_cmp::<_CMP_EQ_UQ>();
+    test_cmp::<_CMP_NGE_US>();
+    test_cmp::<_CMP_NGT_US>();
+    test_cmp::<_CMP_FALSE_OQ>();
+    test_cmp::<_CMP_NEQ_OQ>();
+    test_cmp::<_CMP_GE_OS>();
+    test_cmp::<_CMP_GT_OS>();
+    test_cmp::<_CMP_TRUE_US>();
+}
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs
index c38158dc797..394412a2354 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-avx512.rs
@@ -1,5 +1,5 @@
 // Ignore everything except x86 and x86_64
-// Any additional target are added to CI should be ignored here
+// Any new targets that are added to CI should be ignored here.
 // (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
 //@ignore-target-aarch64
 //@ignore-target-arm
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs
index 0805d9bc300..7566be4431b 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse3-ssse3.rs
@@ -1,5 +1,5 @@
 // Ignore everything except x86 and x86_64
-// Any additional target are added to CI should be ignored here
+// Any new targets that are added to CI should be ignored here.
 // (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
 //@ignore-target-aarch64
 //@ignore-target-arm
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse41.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse41.rs
index 8c565a2d6e0..13856d29d3f 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-sse41.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse41.rs
@@ -1,5 +1,5 @@
 // Ignore everything except x86 and x86_64
-// Any additional target are added to CI should be ignored here
+// Any new targets that are added to CI should be ignored here.
 // (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
 //@ignore-target-aarch64
 //@ignore-target-arm
diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs
index 6386162e095..cb9380f5753 100644
--- a/src/tools/miri/tests/utils/mod.rs
+++ b/src/tools/miri/tests/utils/mod.rs
@@ -7,12 +7,10 @@ mod macros;
 mod fs;
 mod miri_extern;
 
-pub use fs::*;
-pub use miri_extern::*;
+pub use self::fs::*;
+pub use self::miri_extern::*;
 
 pub fn run_provenance_gc() {
     // SAFETY: No preconditions. The GC is fine to run at any time.
-    unsafe {
-        miri_run_provenance_gc()
-    }
+    unsafe { miri_run_provenance_gc() }
 }