about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-21 08:01:45 +0000
committerbors <bors@rust-lang.org>2023-09-21 08:01:45 +0000
commitd2db689e1efa5b3fff6b664b6d2dba0ef65b80e7 (patch)
treee947a059c42ff87214337cc3a825e0b338af394d /src/tools
parent70f3d3e6ad6656546f79fac961ed3a4316003fa3 (diff)
parented8fbcb05910f4439ec572bd163cc99a3603e378 (diff)
downloadrust-d2db689e1efa5b3fff6b664b6d2dba0ef65b80e7.tar.gz
rust-d2db689e1efa5b3fff6b664b6d2dba0ef65b80e7.zip
Auto merge of #3069 - rust-lang:rustup-2023-09-21, r=RalfJung
Automatic sync from rustc
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs2
-rw-r--r--src/tools/compiletest/src/common.rs20
-rw-r--r--src/tools/compiletest/src/header/needs.rs28
-rw-r--r--src/tools/compiletest/src/header/tests.rs234
-rw-r--r--src/tools/compiletest/src/runtest.rs19
-rw-r--r--src/tools/compiletest/src/util.rs102
-rw-r--r--src/tools/miri/Cargo.lock88
-rw-r--r--src/tools/miri/Cargo.toml2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/helpers.rs37
-rw-r--r--src/tools/miri/src/shims/backtrace.rs5
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs19
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs158
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs248
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs380
-rw-r--r--src/tools/rustdoc-js/tester.js4
-rw-r--r--src/tools/rustdoc-themes/main.rs3
-rw-r--r--src/tools/tidy/src/deps.rs2
19 files changed, 567 insertions, 788 deletions
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index fcb90c63a6f..c88fce22f7f 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -656,7 +656,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 }
 
 pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant<'tcx>> {
-    use rustc_middle::mir::interpret::ConstValue;
+    use rustc_middle::mir::ConstValue;
     match result {
         mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
             ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index f0b4ede35fb..9e25d97f5a6 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -13,7 +13,7 @@ use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
-use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::{ConstValue, interpret::Scalar};
 use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index b91d5a958bb..ba273489eb8 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -141,6 +141,22 @@ impl PanicStrategy {
     }
 }
 
+#[derive(Clone, Debug, PartialEq, serde::Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum Sanitizer {
+    Address,
+    Cfi,
+    Kcfi,
+    KernelAddress,
+    Leak,
+    Memory,
+    Memtag,
+    Safestack,
+    ShadowCallStack,
+    Thread,
+    Hwaddress,
+}
+
 /// Configuration for compiletest
 #[derive(Debug, Default, Clone)]
 pub struct Config {
@@ -560,6 +576,10 @@ pub struct TargetCfg {
     pub(crate) panic: PanicStrategy,
     #[serde(default)]
     pub(crate) dynamic_linking: bool,
+    #[serde(rename = "supported-sanitizers", default)]
+    pub(crate) sanitizers: Vec<Sanitizer>,
+    #[serde(rename = "supports-xray", default)]
+    pub(crate) xray: bool,
 }
 
 impl TargetCfg {
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 62364ede47b..1113721fff6 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -1,6 +1,5 @@
-use crate::common::{Config, Debugger};
+use crate::common::{Config, Debugger, Sanitizer};
 use crate::header::IgnoreDecision;
-use crate::util;
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
@@ -220,21 +219,22 @@ impl CachedNeedsConditions {
             path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file());
 
         let target = &&*config.target;
+        let sanitizers = &config.target_cfg().sanitizers;
         Self {
             sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
-            sanitizer_address: util::ASAN_SUPPORTED_TARGETS.contains(target),
-            sanitizer_cfi: util::CFI_SUPPORTED_TARGETS.contains(target),
-            sanitizer_kcfi: util::KCFI_SUPPORTED_TARGETS.contains(target),
-            sanitizer_kasan: util::KASAN_SUPPORTED_TARGETS.contains(target),
-            sanitizer_leak: util::LSAN_SUPPORTED_TARGETS.contains(target),
-            sanitizer_memory: util::MSAN_SUPPORTED_TARGETS.contains(target),
-            sanitizer_thread: util::TSAN_SUPPORTED_TARGETS.contains(target),
-            sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target),
-            sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target),
-            sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target),
-            sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target),
+            sanitizer_address: sanitizers.contains(&Sanitizer::Address),
+            sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi),
+            sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
+            sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
+            sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),
+            sanitizer_memory: sanitizers.contains(&Sanitizer::Memory),
+            sanitizer_thread: sanitizers.contains(&Sanitizer::Thread),
+            sanitizer_hwaddress: sanitizers.contains(&Sanitizer::Hwaddress),
+            sanitizer_memtag: sanitizers.contains(&Sanitizer::Memtag),
+            sanitizer_shadow_call_stack: sanitizers.contains(&Sanitizer::ShadowCallStack),
+            sanitizer_safestack: sanitizers.contains(&Sanitizer::Safestack),
             profiler_support: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(),
-            xray: util::XRAY_SUPPORTED_TARGETS.contains(target),
+            xray: config.target_cfg().xray,
 
             // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
             // whether `rust-lld` is present in the compiler under test.
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 362fba11697..2fd80b52cee 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -53,47 +53,117 @@ fn test_parse_normalization_string() {
     assert_eq!(s, r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."#);
 }
 
-fn config() -> Config {
-    let args = &[
-        "compiletest",
-        "--mode=ui",
-        "--suite=ui",
-        "--compile-lib-path=",
-        "--run-lib-path=",
-        "--python=",
-        "--jsondocck-path=",
-        "--src-base=",
-        "--build-base=",
-        "--sysroot-base=",
-        "--stage-id=stage2-x86_64-unknown-linux-gnu",
-        "--cc=c",
-        "--cxx=c++",
-        "--cflags=",
-        "--cxxflags=",
-        "--llvm-components=",
-        "--android-cross-path=",
-        "--target=x86_64-unknown-linux-gnu",
-        "--channel=nightly",
-    ];
-    let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
-    args.push("--rustc-path".to_string());
-    // This is a subtle/fragile thing. On rust-lang CI, there is no global
-    // `rustc`, and Cargo doesn't offer a convenient way to get the path to
-    // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing
-    // to the stage0 compiler.
-    //
-    // Otherwise, if you are running compiletests's tests manually, you
-    // probably don't have `RUSTC` set, in which case this falls back to the
-    // global rustc. If your global rustc is too far out of sync with stage0,
-    // then this may cause confusing errors. Or if for some reason you don't
-    // have rustc in PATH, that would also fail.
-    args.push(std::env::var("RUSTC").unwrap_or_else(|_| {
-        eprintln!(
-            "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)"
-        );
-        "rustc".to_string()
-    }));
-    crate::parse_config(args)
+#[derive(Default)]
+struct ConfigBuilder {
+    channel: Option<String>,
+    host: Option<String>,
+    target: Option<String>,
+    stage_id: Option<String>,
+    llvm_version: Option<String>,
+    git_hash: bool,
+    system_llvm: bool,
+}
+
+impl ConfigBuilder {
+    fn channel(&mut self, s: &str) -> &mut Self {
+        self.channel = Some(s.to_owned());
+        self
+    }
+
+    fn host(&mut self, s: &str) -> &mut Self {
+        self.host = Some(s.to_owned());
+        self
+    }
+
+    fn target(&mut self, s: &str) -> &mut Self {
+        self.target = Some(s.to_owned());
+        self
+    }
+
+    fn stage_id(&mut self, s: &str) -> &mut Self {
+        self.stage_id = Some(s.to_owned());
+        self
+    }
+
+    fn llvm_version(&mut self, s: &str) -> &mut Self {
+        self.llvm_version = Some(s.to_owned());
+        self
+    }
+
+    fn git_hash(&mut self, b: bool) -> &mut Self {
+        self.git_hash = b;
+        self
+    }
+
+    fn system_llvm(&mut self, s: bool) -> &mut Self {
+        self.system_llvm = s;
+        self
+    }
+
+    fn build(&mut self) -> Config {
+        let args = &[
+            "compiletest",
+            "--mode=ui",
+            "--suite=ui",
+            "--compile-lib-path=",
+            "--run-lib-path=",
+            "--python=",
+            "--jsondocck-path=",
+            "--src-base=",
+            "--build-base=",
+            "--sysroot-base=",
+            "--cc=c",
+            "--cxx=c++",
+            "--cflags=",
+            "--cxxflags=",
+            "--llvm-components=",
+            "--android-cross-path=",
+            "--stage-id",
+            self.stage_id.as_deref().unwrap_or("stage2-x86_64-unknown-linux-gnu"),
+            "--channel",
+            self.channel.as_deref().unwrap_or("nightly"),
+            "--host",
+            self.host.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
+            "--target",
+            self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
+        ];
+        let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
+
+        if let Some(ref llvm_version) = self.llvm_version {
+            args.push("--llvm-version".to_owned());
+            args.push(llvm_version.clone());
+        }
+
+        if self.git_hash {
+            args.push("--git-hash".to_owned());
+        }
+        if self.system_llvm {
+            args.push("--system-llvm".to_owned());
+        }
+
+        args.push("--rustc-path".to_string());
+        // This is a subtle/fragile thing. On rust-lang CI, there is no global
+        // `rustc`, and Cargo doesn't offer a convenient way to get the path to
+        // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing
+        // to the stage0 compiler.
+        //
+        // Otherwise, if you are running compiletests's tests manually, you
+        // probably don't have `RUSTC` set, in which case this falls back to the
+        // global rustc. If your global rustc is too far out of sync with stage0,
+        // then this may cause confusing errors. Or if for some reason you don't
+        // have rustc in PATH, that would also fail.
+        args.push(std::env::var("RUSTC").unwrap_or_else(|_| {
+            eprintln!(
+                "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)"
+            );
+            "rustc".to_string()
+        }));
+        crate::parse_config(args)
+    }
+}
+
+fn cfg() -> ConfigBuilder {
+    ConfigBuilder::default()
 }
 
 fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
@@ -115,7 +185,7 @@ fn parse_makefile(config: &Config, contents: &str) -> EarlyProps {
 
 #[test]
 fn should_fail() {
-    let config = config();
+    let config: Config = cfg().build();
     let tn = test::DynTestName(String::new());
     let p = Path::new("a.rs");
 
@@ -127,7 +197,7 @@ fn should_fail() {
 
 #[test]
 fn revisions() {
-    let config = config();
+    let config: Config = cfg().build();
 
     assert_eq!(parse_rs(&config, "// revisions: a b c").revisions, vec!["a", "b", "c"],);
     assert_eq!(
@@ -138,7 +208,7 @@ fn revisions() {
 
 #[test]
 fn aux_build() {
-    let config = config();
+    let config: Config = cfg().build();
 
     assert_eq!(
         parse_rs(
@@ -155,36 +225,31 @@ fn aux_build() {
 
 #[test]
 fn no_system_llvm() {
-    let mut config = config();
-
-    config.system_llvm = false;
+    let config: Config = cfg().system_llvm(false).build();
     assert!(!check_ignore(&config, "// no-system-llvm"));
 
-    config.system_llvm = true;
+    let config: Config = cfg().system_llvm(true).build();
     assert!(check_ignore(&config, "// no-system-llvm"));
 }
 
 #[test]
 fn llvm_version() {
-    let mut config = config();
-
-    config.llvm_version = Some(80102);
+    let config: Config = cfg().llvm_version("8.1.2").build();
     assert!(check_ignore(&config, "// min-llvm-version: 9.0"));
 
-    config.llvm_version = Some(90001);
+    let config: Config = cfg().llvm_version("9.0.1").build();
     assert!(check_ignore(&config, "// min-llvm-version: 9.2"));
 
-    config.llvm_version = Some(90301);
+    let config: Config = cfg().llvm_version("9.3.1").build();
     assert!(!check_ignore(&config, "// min-llvm-version: 9.2"));
 
-    config.llvm_version = Some(100000);
+    let config: Config = cfg().llvm_version("10.0.0").build();
     assert!(!check_ignore(&config, "// min-llvm-version: 9.0"));
 }
 
 #[test]
 fn ignore_target() {
-    let mut config = config();
-    config.target = "x86_64-unknown-linux-gnu".to_owned();
+    let config: Config = cfg().target("x86_64-unknown-linux-gnu").build();
 
     assert!(check_ignore(&config, "// ignore-x86_64-unknown-linux-gnu"));
     assert!(check_ignore(&config, "// ignore-x86_64"));
@@ -200,8 +265,7 @@ fn ignore_target() {
 
 #[test]
 fn only_target() {
-    let mut config = config();
-    config.target = "x86_64-pc-windows-gnu".to_owned();
+    let config: Config = cfg().target("x86_64-pc-windows-gnu").build();
 
     assert!(check_ignore(&config, "// only-x86"));
     assert!(check_ignore(&config, "// only-linux"));
@@ -217,8 +281,7 @@ fn only_target() {
 
 #[test]
 fn stage() {
-    let mut config = config();
-    config.stage_id = "stage1-x86_64-unknown-linux-gnu".to_owned();
+    let config: Config = cfg().stage_id("stage1-x86_64-unknown-linux-gnu").build();
 
     assert!(check_ignore(&config, "// ignore-stage1"));
     assert!(!check_ignore(&config, "// ignore-stage2"));
@@ -226,18 +289,16 @@ fn stage() {
 
 #[test]
 fn cross_compile() {
-    let mut config = config();
-    config.host = "x86_64-apple-darwin".to_owned();
-    config.target = "wasm32-unknown-unknown".to_owned();
+    let config: Config = cfg().host("x86_64-apple-darwin").target("wasm32-unknown-unknown").build();
     assert!(check_ignore(&config, "// ignore-cross-compile"));
 
-    config.target = config.host.clone();
+    let config: Config = cfg().host("x86_64-apple-darwin").target("x86_64-apple-darwin").build();
     assert!(!check_ignore(&config, "// ignore-cross-compile"));
 }
 
 #[test]
 fn debugger() {
-    let mut config = config();
+    let mut config = cfg().build();
     config.debugger = None;
     assert!(!check_ignore(&config, "// ignore-cdb"));
 
@@ -253,27 +314,24 @@ fn debugger() {
 
 #[test]
 fn git_hash() {
-    let mut config = config();
-    config.git_hash = false;
+    let config: Config = cfg().git_hash(false).build();
     assert!(check_ignore(&config, "// needs-git-hash"));
 
-    config.git_hash = true;
+    let config: Config = cfg().git_hash(true).build();
     assert!(!check_ignore(&config, "// needs-git-hash"));
 }
 
 #[test]
 fn sanitizers() {
-    let mut config = config();
-
     // Target that supports all sanitizers:
-    config.target = "x86_64-unknown-linux-gnu".to_owned();
+    let config: Config = cfg().target("x86_64-unknown-linux-gnu").build();
     assert!(!check_ignore(&config, "// needs-sanitizer-address"));
     assert!(!check_ignore(&config, "// needs-sanitizer-leak"));
     assert!(!check_ignore(&config, "// needs-sanitizer-memory"));
     assert!(!check_ignore(&config, "// needs-sanitizer-thread"));
 
     // Target that doesn't support sanitizers:
-    config.target = "wasm32-unknown-emscripten".to_owned();
+    let config: Config = cfg().target("wasm32-unknown-emscripten").build();
     assert!(check_ignore(&config, "// needs-sanitizer-address"));
     assert!(check_ignore(&config, "// needs-sanitizer-leak"));
     assert!(check_ignore(&config, "// needs-sanitizer-memory"));
@@ -291,8 +349,7 @@ fn asm_support() {
         ("i686-unknown-netbsd", true),
     ];
     for (target, has_asm) in asms {
-        let mut config = config();
-        config.target = target.to_string();
+        let config = cfg().target(target).build();
         assert_eq!(config.has_asm_support(), has_asm);
         assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm)
     }
@@ -300,8 +357,7 @@ fn asm_support() {
 
 #[test]
 fn channel() {
-    let mut config = config();
-    config.channel = "beta".into();
+    let config: Config = cfg().channel("beta").build();
 
     assert!(check_ignore(&config, "// ignore-beta"));
     assert!(check_ignore(&config, "// only-nightly"));
@@ -330,7 +386,7 @@ fn test_extract_version_range() {
 #[test]
 #[should_panic(expected = "Duplicate revision: `rpass1` in line ` rpass1 rpass1`")]
 fn test_duplicate_revisions() {
-    let config = config();
+    let config: Config = cfg().build();
     parse_rs(&config, "// revisions: rpass1 rpass1");
 }
 
@@ -345,8 +401,7 @@ fn ignore_arch() {
         ("thumbv7m-none-eabi", "thumb"),
     ];
     for (target, arch) in archs {
-        let mut config = config();
-        config.target = target.to_string();
+        let config: Config = cfg().target(target).build();
         assert!(config.matches_arch(arch), "{target} {arch}");
         assert!(check_ignore(&config, &format!("// ignore-{arch}")));
     }
@@ -361,8 +416,7 @@ fn matches_os() {
         ("x86_64-unknown-none", "none"),
     ];
     for (target, os) in oss {
-        let mut config = config();
-        config.target = target.to_string();
+        let config = cfg().target(target).build();
         assert!(config.matches_os(os), "{target} {os}");
         assert!(check_ignore(&config, &format!("// ignore-{os}")));
     }
@@ -376,8 +430,7 @@ fn matches_env() {
         ("arm-unknown-linux-musleabi", "musl"),
     ];
     for (target, env) in envs {
-        let mut config = config();
-        config.target = target.to_string();
+        let config: Config = cfg().target(target).build();
         assert!(config.matches_env(env), "{target} {env}");
         assert!(check_ignore(&config, &format!("// ignore-{env}")));
     }
@@ -391,8 +444,7 @@ fn matches_abi() {
         ("arm-unknown-linux-gnueabi", "eabi"),
     ];
     for (target, abi) in abis {
-        let mut config = config();
-        config.target = target.to_string();
+        let config: Config = cfg().target(target).build();
         assert!(config.matches_abi(abi), "{target} {abi}");
         assert!(check_ignore(&config, &format!("// ignore-{abi}")));
     }
@@ -408,8 +460,7 @@ fn is_big_endian() {
         ("powerpc64-unknown-linux-gnu", true),
     ];
     for (target, is_big) in endians {
-        let mut config = config();
-        config.target = target.to_string();
+        let config = cfg().target(target).build();
         assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}");
         assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big);
     }
@@ -424,8 +475,7 @@ fn pointer_width() {
         ("msp430-none-elf", 16),
     ];
     for (target, width) in widths {
-        let mut config = config();
-        config.target = target.to_string();
+        let config: Config = cfg().target(target).build();
         assert_eq!(config.get_pointer_width(), width, "{target} {width}");
         assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16);
         assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32);
@@ -456,8 +506,7 @@ fn wasm_special() {
         ("wasm64-unknown-unknown", "wasm64", true),
     ];
     for (target, pattern, ignore) in ignores {
-        let mut config = config();
-        config.target = target.to_string();
+        let config: Config = cfg().target(target).build();
         assert_eq!(
             check_ignore(&config, &format!("// ignore-{pattern}")),
             ignore,
@@ -476,8 +525,7 @@ fn families() {
         ("wasm32-unknown-emscripten", "unix"),
     ];
     for (target, family) in families {
-        let mut config = config();
-        config.target = target.to_string();
+        let config: Config = cfg().target(target).build();
         assert!(config.matches_family(family));
         let other = if family == "windows" { "unix" } else { "windows" };
         assert!(!config.matches_family(other));
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 7b42d8e9b58..657d074b380 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2335,14 +2335,17 @@ impl<'test> TestCx<'test> {
         rustc.arg("-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX");
         rustc.arg("-Ztranslate-remapped-path-to-local-path=no");
 
-        // Hide Cargo dependency sources from ui tests to make sure the error message doesn't
-        // change depending on whether $CARGO_HOME is remapped or not. If this is not present,
-        // when $CARGO_HOME is remapped the source won't be shown, and when it's not remapped the
-        // source will be shown, causing a blessing hell.
-        rustc.arg("-Z").arg(format!(
-            "ignore-directory-in-diagnostics-source-blocks={}",
-            home::cargo_home().expect("failed to find cargo home").to_str().unwrap()
-        ));
+        // #[cfg(not(bootstrap))]: After beta bump, this should **always** run.
+        if !(self.config.stage_id.starts_with("stage1-") && self.config.suite == "ui-fulldeps") {
+            // Hide Cargo dependency sources from ui tests to make sure the error message doesn't
+            // change depending on whether $CARGO_HOME is remapped or not. If this is not present,
+            // when $CARGO_HOME is remapped the source won't be shown, and when it's not remapped the
+            // source will be shown, causing a blessing hell.
+            rustc.arg("-Z").arg(format!(
+                "ignore-directory-in-diagnostics-source-blocks={}",
+                home::cargo_home().expect("failed to find cargo home").to_str().unwrap()
+            ));
+        }
 
         // Optionally prevent default --sysroot if specified in test compile-flags.
         if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot"))
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 02648fe5c29..8f9425eb071 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -9,108 +9,6 @@ use tracing::*;
 #[cfg(test)]
 mod tests;
 
-pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
-    "aarch64-apple-darwin",
-    "aarch64-apple-ios",
-    "aarch64-apple-ios-sim",
-    "aarch64-apple-ios-macabi",
-    "aarch64-unknown-fuchsia",
-    "aarch64-linux-android",
-    "aarch64-unknown-linux-gnu",
-    "arm-linux-androideabi",
-    "armv7-linux-androideabi",
-    "i686-linux-android",
-    "i686-unknown-linux-gnu",
-    "x86_64-apple-darwin",
-    "x86_64-apple-ios",
-    "x86_64-apple-ios-macabi",
-    "x86_64-unknown-fuchsia",
-    "x86_64-linux-android",
-    "x86_64-unknown-freebsd",
-    "x86_64-unknown-linux-gnu",
-    "s390x-unknown-linux-gnu",
-];
-
-// FIXME(rcvalle): More targets are likely supported.
-pub const CFI_SUPPORTED_TARGETS: &[&str] = &[
-    "aarch64-apple-darwin",
-    "aarch64-unknown-fuchsia",
-    "aarch64-linux-android",
-    "aarch64-unknown-freebsd",
-    "aarch64-unknown-linux-gnu",
-    "x86_64-apple-darwin",
-    "x86_64-unknown-fuchsia",
-    "x86_64-pc-solaris",
-    "x86_64-unknown-freebsd",
-    "x86_64-unknown-illumos",
-    "x86_64-unknown-linux-gnu",
-    "x86_64-unknown-linux-musl",
-    "x86_64-unknown-netbsd",
-];
-
-pub const KCFI_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-none", "x86_64-linux-none"];
-
-pub const KASAN_SUPPORTED_TARGETS: &[&str] = &[
-    "aarch64-unknown-none",
-    "riscv64gc-unknown-none-elf",
-    "riscv64imac-unknown-none-elf",
-    "x86_64-unknown-none",
-];
-
-pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
-    // FIXME: currently broken, see #88132
-    // "aarch64-apple-darwin",
-    "aarch64-unknown-linux-gnu",
-    "x86_64-apple-darwin",
-    "x86_64-apple-ios-macabi",
-    "x86_64-unknown-linux-gnu",
-    "s390x-unknown-linux-gnu",
-];
-
-pub const MSAN_SUPPORTED_TARGETS: &[&str] = &[
-    "aarch64-unknown-linux-gnu",
-    "x86_64-unknown-freebsd",
-    "x86_64-unknown-linux-gnu",
-    "s390x-unknown-linux-gnu",
-];
-
-pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
-    "aarch64-apple-darwin",
-    "aarch64-apple-ios",
-    "aarch64-apple-ios-sim",
-    "aarch64-apple-ios-macabi",
-    "aarch64-unknown-linux-gnu",
-    "x86_64-apple-darwin",
-    "x86_64-apple-ios",
-    "x86_64-apple-ios-macabi",
-    "x86_64-unknown-freebsd",
-    "x86_64-unknown-linux-gnu",
-    "s390x-unknown-linux-gnu",
-];
-
-pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
-    &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
-
-pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
-    &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
-
-pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
-
-pub const XRAY_SUPPORTED_TARGETS: &[&str] = &[
-    "aarch64-linux-android",
-    "aarch64-unknown-linux-gnu",
-    "aarch64-unknown-linux-musl",
-    "x86_64-linux-android",
-    "x86_64-unknown-freebsd",
-    "x86_64-unknown-linux-gnu",
-    "x86_64-unknown-linux-musl",
-    "x86_64-unknown-netbsd",
-    "x86_64-unknown-none-linuxkernel",
-    "x86_64-unknown-openbsd",
-];
-
-pub const SAFESTACK_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
-
 pub fn make_new_path(path: &str) -> String {
     assert!(cfg!(windows));
     // Windows just uses PATH as the library search path, so we have to
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index ca5b6d22515..f253d71e50d 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -33,17 +33,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
 
 [[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi 0.1.19",
- "libc",
- "winapi",
-]
-
-[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -71,6 +60,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
+name = "bitflags"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+
+[[package]]
 name = "bstr"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -155,13 +150,13 @@ dependencies = [
 
 [[package]]
 name = "colored"
-version = "2.0.0"
+version = "2.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
+checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
 dependencies = [
- "atty",
+ "is-terminal",
  "lazy_static",
- "winapi",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -201,12 +196,12 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
 
 [[package]]
 name = "env_logger"
-version = "0.9.3"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
 dependencies = [
- "atty",
  "humantime",
+ "is-terminal",
  "log",
  "regex",
  "termcolor",
@@ -271,15 +266,6 @@ checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "hermit-abi"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
@@ -311,12 +297,23 @@ version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
 dependencies = [
- "hermit-abi 0.3.1",
+ "hermit-abi",
  "libc",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
+name = "is-terminal"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+dependencies = [
+ "hermit-abi",
+ "rustix 0.38.14",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "itoa"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -330,9 +327,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.142"
+version = "0.2.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
+checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
 
 [[package]]
 name = "libffi"
@@ -370,6 +367,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
 
 [[package]]
+name = "linux-raw-sys"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
+
+[[package]]
 name = "lock_api"
 version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -454,7 +457,7 @@ version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
  "cfg-if",
  "libc",
  "static_assertions",
@@ -581,7 +584,7 @@ version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
 ]
 
 [[package]]
@@ -590,7 +593,7 @@ version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
 ]
 
 [[package]]
@@ -655,11 +658,24 @@ version = "0.37.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
  "errno",
  "io-lifetimes",
  "libc",
- "linux-raw-sys",
+ "linux-raw-sys 0.3.7",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
+dependencies = [
+ "bitflags 2.4.0",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.7",
  "windows-sys 0.48.0",
 ]
 
@@ -756,7 +772,7 @@ dependencies = [
  "cfg-if",
  "fastrand",
  "redox_syscall 0.3.5",
- "rustix",
+ "rustix 0.37.19",
  "windows-sys 0.45.0",
 ]
 
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 67a2aeefa02..2ae6f922e3a 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -19,7 +19,7 @@ doctest = false # and no doc tests
 
 [dependencies]
 getrandom = { version = "0.2", features = ["std"] }
-env_logger = "0.9"
+env_logger = "0.10"
 log = "0.4"
 rand = "0.8"
 smallvec = "1.7"
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index a2030c1c343..f6db58695fb 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-19dd9535408db0f1ff3d16613619076aef524d19
+4fda889bf8735755573b27e6116ce025f3ded5f9
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 72d9dbd045d..b05087134a0 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir;
 use rustc_middle::ty::{
     self,
     layout::{IntegerExt as _, LayoutOf, TyAndLayout},
-    Ty, TyCtxt,
+    IntTy, Ty, TyCtxt, UintTy,
 };
 use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
 use rustc_target::abi::{Align, FieldIdx, FieldsShape, Integer, Size, Variants};
@@ -1066,6 +1066,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 ),
         }
     }
+
+    /// Returns an integer type that is twice wide as `ty`
+    fn get_twice_wide_int_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let this = self.eval_context_ref();
+        match ty.kind() {
+            // Unsigned
+            ty::Uint(UintTy::U8) => this.tcx.types.u16,
+            ty::Uint(UintTy::U16) => this.tcx.types.u32,
+            ty::Uint(UintTy::U32) => this.tcx.types.u64,
+            ty::Uint(UintTy::U64) => this.tcx.types.u128,
+            // Signed
+            ty::Int(IntTy::I8) => this.tcx.types.i16,
+            ty::Int(IntTy::I16) => this.tcx.types.i32,
+            ty::Int(IntTy::I32) => this.tcx.types.i64,
+            ty::Int(IntTy::I64) => this.tcx.types.i128,
+            _ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
+        }
+    }
 }
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@@ -1151,3 +1169,20 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
 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
+    // sign-extend it to `size` as required.
+    let val = if b { -1 } else { 0 };
+    Scalar::from_int(val, size)
+}
+
+pub(crate) fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> {
+    let val = elem.to_scalar().to_int(elem.layout.size)?;
+    Ok(match val {
+        0 => false,
+        -1 => true,
+        _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"),
+    })
+}
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index bfec4833ac9..ee2edd462d1 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -88,10 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.write_pointer(ptr, &place)?;
                 }
 
-                this.write_immediate(
-                    Immediate::new_slice(Scalar::from_maybe_pointer(alloc.ptr(), this), len, this),
-                    dest,
-                )?;
+                this.write_immediate(Immediate::new_slice(alloc.ptr(), len, this), dest)?;
             }
             // storage for pointers is allocated by the caller
             1 => {
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index dd8c4a4f6ec..626ead378e7 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -1,10 +1,10 @@
 use rustc_apfloat::{Float, Round};
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::{mir, ty, ty::FloatTy};
-use rustc_target::abi::{Endian, HasDataLayout, Size};
+use rustc_target::abi::{Endian, HasDataLayout};
 
 use crate::*;
-use helpers::check_arg_count;
+use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool};
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
@@ -612,21 +612,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     }
 }
 
-fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> {
-    // SIMD uses all-1 as pattern for "true"
-    let val = if b { -1 } else { 0 };
-    Scalar::from_int(val, size)
-}
-
-fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> {
-    let val = elem.to_scalar().to_int(elem.layout.size)?;
-    Ok(match val {
-        0 => false,
-        -1 => true,
-        _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"),
-    })
-}
-
 fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
     assert!(idx < vec_len);
     match endianness {
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 62f5eb1baf7..ccc729aae1a 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,4 +1,8 @@
-use crate::InterpResult;
+use rustc_middle::mir;
+use rustc_target::abi::Size;
+
+use crate::*;
+use helpers::bool_to_simd_element;
 
 pub(super) mod sse;
 pub(super) mod sse2;
@@ -43,3 +47,155 @@ impl FloatCmpOp {
         }
     }
 }
+
+#[derive(Copy, Clone)]
+enum FloatBinOp {
+    /// Arithmetic operation
+    Arith(mir::BinOp),
+    /// Comparison
+    Cmp(FloatCmpOp),
+    /// Minimum value (with SSE semantics)
+    ///
+    /// <https://www.felixcloutier.com/x86/minss>
+    /// <https://www.felixcloutier.com/x86/minps>
+    /// <https://www.felixcloutier.com/x86/minsd>
+    /// <https://www.felixcloutier.com/x86/minpd>
+    Min,
+    /// Maximum value (with SSE semantics)
+    ///
+    /// <https://www.felixcloutier.com/x86/maxss>
+    /// <https://www.felixcloutier.com/x86/maxps>
+    /// <https://www.felixcloutier.com/x86/maxsd>
+    /// <https://www.felixcloutier.com/x86/maxpd>
+    Max,
+}
+
+/// Performs `which` scalar operation on `left` and `right` and returns
+/// the result.
+fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
+    this: &crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &ImmTy<'tcx, Provenance>,
+    right: &ImmTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, Scalar<Provenance>> {
+    match which {
+        FloatBinOp::Arith(which) => {
+            let (res, _overflow, _ty) = this.overflowing_binary_op(which, left, right)?;
+            Ok(res)
+        }
+        FloatBinOp::Cmp(which) => {
+            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(),
+            };
+            Ok(bool_to_simd_element(res, Size::from_bits(F::BITS)))
+        }
+        FloatBinOp::Min => {
+            let left_scalar = left.to_scalar();
+            let left = left_scalar.to_float::<F>()?;
+            let right_scalar = right.to_scalar();
+            let right = right_scalar.to_float::<F>()?;
+            // SSE semantics to handle zero and NaN. Note that `x == F::ZERO`
+            // is true when `x` is either +0 or -0.
+            if (left == F::ZERO && right == F::ZERO)
+                || left.is_nan()
+                || right.is_nan()
+                || left >= right
+            {
+                Ok(right_scalar)
+            } else {
+                Ok(left_scalar)
+            }
+        }
+        FloatBinOp::Max => {
+            let left_scalar = left.to_scalar();
+            let left = left_scalar.to_float::<F>()?;
+            let right_scalar = right.to_scalar();
+            let right = right_scalar.to_float::<F>()?;
+            // SSE semantics to handle zero and NaN. Note that `x == F::ZERO`
+            // is true when `x` is either +0 or -0.
+            if (left == F::ZERO && right == F::ZERO)
+                || left.is_nan()
+                || right.is_nan()
+                || left <= right
+            {
+                Ok(right_scalar)
+            } else {
+                Ok(left_scalar)
+            }
+        }
+    }
+}
+
+/// Performs `which` operation on the first component of `left` and `right`
+/// and copies the other components from `left`. The result is stored in `dest`.
+fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (right, right_len) = this.operand_to_simd(right)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    assert_eq!(dest_len, right_len);
+
+    let res0 = bin_op_float::<F>(
+        this,
+        which,
+        &this.read_immediate(&this.project_index(&left, 0)?)?,
+        &this.read_immediate(&this.project_index(&right, 0)?)?,
+    )?;
+    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+    for i in 1..dest_len {
+        this.copy_op(
+            &this.project_index(&left, i)?,
+            &this.project_index(&dest, i)?,
+            /*allow_transmute*/ false,
+        )?;
+    }
+
+    Ok(())
+}
+
+/// Performs `which` operation on each component of `left` and
+/// `right`, storing the result is stored in `dest`.
+fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (right, right_len) = this.operand_to_simd(right)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    assert_eq!(dest_len, right_len);
+
+    for i in 0..dest_len {
+        let left = this.read_immediate(&this.project_index(&left, i)?)?;
+        let right = this.read_immediate(&this.project_index(&right, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        let res = bin_op_float::<F>(this, which, &left, &right)?;
+        this.write_scalar(res, &dest)?;
+    }
+
+    Ok(())
+}
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index ff4bd369706..30ad088206a 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::FloatCmpOp;
+use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
 use crate::*;
 use shims::foreign_items::EmulateByNameResult;
 
@@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                bin_op_ss(this, which, left, right, dest)?;
+                bin_op_simd_float_first::<Single>(this, which, left, right, dest)?;
             }
             // Used to implement _mm_min_ps and _mm_max_ps functions.
             // Note that the semantics are a bit different from Rust simd_min
@@ -62,7 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                bin_op_ps(this, which, left, right, dest)?;
+                bin_op_simd_float_all::<Single>(this, which, left, right, dest)?;
             }
             // Used to implement _mm_{sqrt,rcp,rsqrt}_ss functions.
             // Performs the operations on the first component of `op` and
@@ -106,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "llvm.x86.sse.cmp.ss",
                 )?);
 
-                bin_op_ss(this, which, left, right, dest)?;
+                bin_op_simd_float_first::<Single>(this, which, left, right, dest)?;
             }
             // Used to implement the _mm_cmp_ps function.
             // Performs a comparison operation on each component of `left`
@@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "llvm.x86.sse.cmp.ps",
                 )?);
 
-                bin_op_ps(this, which, left, right, dest)?;
+                bin_op_simd_float_all::<Single>(this, which, left, right, dest)?;
             }
             // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ss functions.
             // Compares the first component of `left` and `right` and returns
@@ -154,9 +154,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 };
                 this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?;
             }
-            // Use to implement _mm_cvtss_si32 and _mm_cvttss_si32.
-            // Converts the first component of `op` from f32 to i32.
-            "cvtss2si" | "cvttss2si" => {
+            // Use to implement the _mm_cvtss_si32, _mm_cvttss_si32,
+            // _mm_cvtss_si64 and _mm_cvttss_si64 functions.
+            // Converts the first component of `op` from f32 to i32/i64.
+            "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => {
                 let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let (op, _) = this.operand_to_simd(op)?;
 
@@ -165,77 +166,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
                     // https://www.felixcloutier.com/x86/cvtss2si
-                    "cvtss2si" => rustc_apfloat::Round::NearestTiesToEven,
+                    "cvtss2si" | "cvtss2si64" => rustc_apfloat::Round::NearestTiesToEven,
                     // always truncate
                     // https://www.felixcloutier.com/x86/cvttss2si
-                    "cvttss2si" => rustc_apfloat::Round::TowardZero,
+                    "cvttss2si" | "cvttss2si64" => rustc_apfloat::Round::TowardZero,
                     _ => unreachable!(),
                 };
 
                 let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
                     // Fallback to minimum acording to SSE semantics.
-                    Scalar::from_i32(i32::MIN)
+                    Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size)
                 });
 
                 this.write_scalar(res, dest)?;
             }
-            // Use to implement _mm_cvtss_si64 and _mm_cvttss_si64.
-            // Converts the first component of `op` from f32 to i64.
-            "cvtss2si64" | "cvttss2si64" => {
-                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 rnd = match unprefixed_name {
-                    // "current SSE rounding mode", assume nearest
-                    // https://www.felixcloutier.com/x86/cvtss2si
-                    "cvtss2si64" => rustc_apfloat::Round::NearestTiesToEven,
-                    // always truncate
-                    // https://www.felixcloutier.com/x86/cvttss2si
-                    "cvttss2si64" => rustc_apfloat::Round::TowardZero,
-                    _ => unreachable!(),
-                };
-
-                let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
-                    // Fallback to minimum acording to SSE semantics.
-                    Scalar::from_i64(i64::MIN)
-                });
-
-                this.write_scalar(res, dest)?;
-            }
-            // Used to implement the _mm_cvtsi32_ss function.
-            // Converts `right` from i32 to f32. Returns a SIMD vector with
-            // the result in the first component and the remaining components
-            // are copied from `left`.
-            // https://www.felixcloutier.com/x86/cvtsi2ss
-            "cvtsi2ss" => {
-                let [left, right] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (dest, dest_len) = this.place_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-
-                let right = this.read_scalar(right)?.to_i32()?;
-
-                let res0 = Scalar::from_f32(Single::from_i128(right.into()).value);
-                this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
-
-                for i in 1..dest_len {
-                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    this.write_immediate(*left, &dest)?;
-                }
-            }
-            // Used to implement the _mm_cvtsi64_ss function.
-            // Converts `right` from i64 to f32. Returns a SIMD vector with
+            // Used to implement the _mm_cvtsi32_ss and _mm_cvtsi64_ss functions.
+            // Converts `right` from i32/i64 to f32. Returns a SIMD vector with
             // the result in the first component and the remaining components
             // are copied from `left`.
             // https://www.felixcloutier.com/x86/cvtsi2ss
-            "cvtsi642ss" => {
+            "cvtsi2ss" | "cvtsi642ss" => {
                 let [left, right] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
@@ -244,16 +194,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 assert_eq!(dest_len, left_len);
 
-                let right = this.read_scalar(right)?.to_i64()?;
-
-                let res0 = Scalar::from_f32(Single::from_i128(right.into()).value);
-                this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+                let right = this.read_immediate(right)?;
+                let dest0 = this.project_index(&dest, 0)?;
+                let res0 = this.int_to_int_or_float(&right, dest0.layout.ty)?;
+                this.write_immediate(res0, &dest0)?;
 
                 for i in 1..dest_len {
-                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
-                    let dest = this.project_index(&dest, i)?;
-
-                    this.write_immediate(*left, &dest)?;
+                    this.copy_op(
+                        &this.project_index(&left, i)?,
+                        &this.project_index(&dest, i)?,
+                        /*allow_transmute*/ false,
+                    )?;
                 }
             }
             // Used to implement the _mm_movemask_ps function.
@@ -282,148 +233,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 }
 
 #[derive(Copy, Clone)]
-enum FloatBinOp {
-    /// Arithmetic operation
-    Arith(mir::BinOp),
-    /// Comparison
-    Cmp(FloatCmpOp),
-    /// Minimum value (with SSE semantics)
-    ///
-    /// <https://www.felixcloutier.com/x86/minss>
-    /// <https://www.felixcloutier.com/x86/minps>
-    Min,
-    /// Maximum value (with SSE semantics)
-    ///
-    /// <https://www.felixcloutier.com/x86/maxss>
-    /// <https://www.felixcloutier.com/x86/maxps>
-    Max,
-}
-
-/// Performs `which` scalar operation on `left` and `right` and returns
-/// the result.
-fn bin_op_f32<'tcx>(
-    this: &crate::MiriInterpCx<'_, 'tcx>,
-    which: FloatBinOp,
-    left: &ImmTy<'tcx, Provenance>,
-    right: &ImmTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, Scalar<Provenance>> {
-    match which {
-        FloatBinOp::Arith(which) => {
-            let (res, _, _) = this.overflowing_binary_op(which, left, right)?;
-            Ok(res)
-        }
-        FloatBinOp::Cmp(which) => {
-            let left = left.to_scalar().to_f32()?;
-            let right = right.to_scalar().to_f32()?;
-            // FIXME: Make sure that these operations match the semantics of cmpps
-            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(),
-            };
-            Ok(Scalar::from_u32(if res { u32::MAX } else { 0 }))
-        }
-        FloatBinOp::Min => {
-            let left = left.to_scalar().to_f32()?;
-            let right = right.to_scalar().to_f32()?;
-            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
-            // is true when `x` is either +0 or -0.
-            if (left == Single::ZERO && right == Single::ZERO)
-                || left.is_nan()
-                || right.is_nan()
-                || left >= right
-            {
-                Ok(Scalar::from_f32(right))
-            } else {
-                Ok(Scalar::from_f32(left))
-            }
-        }
-        FloatBinOp::Max => {
-            let left = left.to_scalar().to_f32()?;
-            let right = right.to_scalar().to_f32()?;
-            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
-            // is true when `x` is either +0 or -0.
-            if (left == Single::ZERO && right == Single::ZERO)
-                || left.is_nan()
-                || right.is_nan()
-                || left <= right
-            {
-                Ok(Scalar::from_f32(right))
-            } else {
-                Ok(Scalar::from_f32(left))
-            }
-        }
-    }
-}
-
-/// Performs `which` operation on the first component of `left` and `right`
-/// and copies the other components from `left`. The result is stored in `dest`.
-fn bin_op_ss<'tcx>(
-    this: &mut crate::MiriInterpCx<'_, 'tcx>,
-    which: FloatBinOp,
-    left: &OpTy<'tcx, Provenance>,
-    right: &OpTy<'tcx, Provenance>,
-    dest: &PlaceTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, ()> {
-    let (left, left_len) = this.operand_to_simd(left)?;
-    let (right, right_len) = this.operand_to_simd(right)?;
-    let (dest, dest_len) = this.place_to_simd(dest)?;
-
-    assert_eq!(dest_len, left_len);
-    assert_eq!(dest_len, right_len);
-
-    let res0 = bin_op_f32(
-        this,
-        which,
-        &this.read_immediate(&this.project_index(&left, 0)?)?,
-        &this.read_immediate(&this.project_index(&right, 0)?)?,
-    )?;
-    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
-
-    for i in 1..dest_len {
-        let left = this.read_immediate(&this.project_index(&left, i)?)?;
-        let dest = this.project_index(&dest, i)?;
-
-        this.write_immediate(*left, &dest)?;
-    }
-
-    Ok(())
-}
-
-/// Performs `which` operation on each component of `left` and
-/// `right`, storing the result is stored in `dest`.
-fn bin_op_ps<'tcx>(
-    this: &mut crate::MiriInterpCx<'_, 'tcx>,
-    which: FloatBinOp,
-    left: &OpTy<'tcx, Provenance>,
-    right: &OpTy<'tcx, Provenance>,
-    dest: &PlaceTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, ()> {
-    let (left, left_len) = this.operand_to_simd(left)?;
-    let (right, right_len) = this.operand_to_simd(right)?;
-    let (dest, dest_len) = this.place_to_simd(dest)?;
-
-    assert_eq!(dest_len, left_len);
-    assert_eq!(dest_len, right_len);
-
-    for i in 0..dest_len {
-        let left = this.read_immediate(&this.project_index(&left, i)?)?;
-        let right = this.read_immediate(&this.project_index(&right, i)?)?;
-        let dest = this.project_index(&dest, i)?;
-
-        let res = bin_op_f32(this, which, &left, &right)?;
-        this.write_scalar(res, &dest)?;
-    }
-
-    Ok(())
-}
-
-#[derive(Copy, Clone)]
 enum FloatUnaryOp {
     /// sqrt(x)
     ///
@@ -510,10 +319,11 @@ fn unary_op_ss<'tcx>(
     this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
 
     for i in 1..dest_len {
-        let op = this.read_immediate(&this.project_index(&op, i)?)?;
-        let dest = this.project_index(&dest, i)?;
-
-        this.write_immediate(*op, &dest)?;
+        this.copy_op(
+            &this.project_index(&op, i)?,
+            &this.project_index(&dest, i)?,
+            /*allow_transmute*/ false,
+        )?;
     }
 
     Ok(())
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 5b42339e648..d3bfb53afd2 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -1,14 +1,14 @@
 use rustc_apfloat::{
     ieee::{Double, Single},
-    Float as _, FloatConvert as _,
+    Float as _,
 };
+use rustc_middle::mir;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
-use super::FloatCmpOp;
+use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
 use crate::*;
 use shims::foreign_items::EmulateByNameResult;
 
@@ -37,9 +37,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         // Intrinsincs sufixed with "epiX" or "epuX" operate with X-bit signed or unsigned
         // vectors.
         match unprefixed_name {
-            // Used to implement the _mm_avg_epu8 function.
-            // Averages packed unsigned 8-bit integers in `left` and `right`.
-            "pavg.b" => {
+            // Used to implement the _mm_avg_epu8 and _mm_avg_epu16 functions.
+            // Averages packed unsigned 8/16-bit integers in `left` and `right`.
+            "pavg.b" | "pavg.w" => {
                 let [left, right] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
@@ -51,50 +51,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 assert_eq!(dest_len, right_len);
 
                 for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u8()?;
-                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?;
+                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
+                    let right = this.read_immediate(&this.project_index(&right, i)?)?;
                     let dest = this.project_index(&dest, i)?;
 
-                    // Values are expanded from u8 to u16, so adds cannot overflow.
-                    let res = u16::from(left)
-                        .checked_add(u16::from(right))
-                        .unwrap()
-                        .checked_add(1)
-                        .unwrap()
-                        / 2;
-                    this.write_scalar(Scalar::from_u8(res.try_into().unwrap()), &dest)?;
-                }
-            }
-            // Used to implement the _mm_avg_epu16 function.
-            // Averages packed unsigned 16-bit integers in `left` and `right`.
-            "pavg.w" => {
-                let [left, right] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (right, right_len) = this.operand_to_simd(right)?;
-                let (dest, dest_len) = this.place_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-                assert_eq!(dest_len, right_len);
+                    // Widen the operands to avoid overflow
+                    let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty);
+                    let twice_wide_layout = this.layout_of(twice_wide_ty)?;
+                    let left = this.int_to_int_or_float(&left, twice_wide_ty)?;
+                    let right = this.int_to_int_or_float(&right, twice_wide_ty)?;
+
+                    // Calculate left + right + 1
+                    let (added, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Add,
+                        &ImmTy::from_immediate(left, twice_wide_layout),
+                        &ImmTy::from_immediate(right, twice_wide_layout),
+                    )?;
+                    let (added, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Add,
+                        &ImmTy::from_scalar(added, twice_wide_layout),
+                        &ImmTy::from_uint(1u32, twice_wide_layout),
+                    )?;
 
-                for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
-                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u16()?;
-                    let dest = this.project_index(&dest, i)?;
+                    // Calculate (left + right + 1) / 2
+                    let (divided, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Div,
+                        &ImmTy::from_scalar(added, twice_wide_layout),
+                        &ImmTy::from_uint(2u32, twice_wide_layout),
+                    )?;
 
-                    // Values are expanded from u16 to u32, so adds cannot overflow.
-                    let res = u32::from(left)
-                        .checked_add(u32::from(right))
-                        .unwrap()
-                        .checked_add(1)
-                        .unwrap()
-                        / 2;
-                    this.write_scalar(Scalar::from_u16(res.try_into().unwrap()), &dest)?;
+                    // Narrow back to the original type
+                    let res = this.int_to_int_or_float(
+                        &ImmTy::from_scalar(divided, twice_wide_layout),
+                        dest.layout.ty,
+                    )?;
+                    this.write_immediate(res, &dest)?;
                 }
             }
-            // Used to implement the _mm_mulhi_epi16 function.
-            "pmulh.w" => {
+            // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions.
+            "pmulh.w" | "pmulhu.w" => {
                 let [left, right] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
@@ -106,35 +101,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 assert_eq!(dest_len, right_len);
 
                 for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
-                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
+                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
+                    let right = this.read_immediate(&this.project_index(&right, i)?)?;
                     let dest = this.project_index(&dest, i)?;
 
-                    // Values are expanded from i16 to i32, so multiplication cannot overflow.
-                    let res = i32::from(left).checked_mul(i32::from(right)).unwrap() >> 16;
-                    this.write_scalar(Scalar::from_int(res, Size::from_bits(16)), &dest)?;
-                }
-            }
-            // Used to implement the _mm_mulhi_epu16 function.
-            "pmulhu.w" => {
-                let [left, right] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (right, right_len) = this.operand_to_simd(right)?;
-                let (dest, dest_len) = this.place_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-                assert_eq!(dest_len, right_len);
-
-                for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
-                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u16()?;
-                    let dest = this.project_index(&dest, i)?;
+                    // Widen the operands to avoid overflow
+                    let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty);
+                    let twice_wide_layout = this.layout_of(twice_wide_ty)?;
+                    let left = this.int_to_int_or_float(&left, twice_wide_ty)?;
+                    let right = this.int_to_int_or_float(&right, twice_wide_ty)?;
+
+                    // Multiply
+                    let (multiplied, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Mul,
+                        &ImmTy::from_immediate(left, twice_wide_layout),
+                        &ImmTy::from_immediate(right, twice_wide_layout),
+                    )?;
+                    // Keep the high half
+                    let (high, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Shr,
+                        &ImmTy::from_scalar(multiplied, twice_wide_layout),
+                        &ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout),
+                    )?;
 
-                    // Values are expanded from u16 to u32, so multiplication cannot overflow.
-                    let res = u32::from(left).checked_mul(u32::from(right)).unwrap() >> 16;
-                    this.write_scalar(Scalar::from_u16(res.try_into().unwrap()), &dest)?;
+                    // Narrow back to the original type
+                    let res = this.int_to_int_or_float(
+                        &ImmTy::from_scalar(high, twice_wide_layout),
+                        dest.layout.ty,
+                    )?;
+                    this.write_immediate(res, &dest)?;
                 }
             }
             // Used to implement the _mm_mul_epu32 function.
@@ -431,11 +426,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let right_res =
                         i8::try_from(right).unwrap_or(if right < 0 { i8::MIN } else { i8::MAX });
 
-                    this.write_scalar(Scalar::from_int(left_res, Size::from_bits(8)), &left_dest)?;
-                    this.write_scalar(
-                        Scalar::from_int(right_res, Size::from_bits(8)),
-                        &right_dest,
-                    )?;
+                    this.write_scalar(Scalar::from_i8(left_res), &left_dest)?;
+                    this.write_scalar(Scalar::from_i8(right_res), &right_dest)?;
                 }
             }
             // Used to implement the _mm_packus_epi16 function.
@@ -469,7 +461,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 }
             }
             // Used to implement the _mm_packs_epi32 function.
-            // Converts two 16-bit integer vectors to a single 8-bit integer
+            // Converts two 32-bit integer vectors to a single 16-bit integer
             // vector with signed saturation.
             "packssdw.128" => {
                 let [left, right] =
@@ -495,11 +487,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     let right_res =
                         i16::try_from(right).unwrap_or(if right < 0 { i16::MIN } else { i16::MAX });
 
-                    this.write_scalar(Scalar::from_int(left_res, Size::from_bits(16)), &left_dest)?;
-                    this.write_scalar(
-                        Scalar::from_int(right_res, Size::from_bits(16)),
-                        &right_dest,
-                    )?;
+                    this.write_scalar(Scalar::from_i16(left_res), &left_dest)?;
+                    this.write_scalar(Scalar::from_i16(right_res), &right_dest)?;
                 }
             }
             // Used to implement _mm_min_sd and _mm_max_sd functions.
@@ -517,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                bin_op_sd(this, which, left, right, dest)?;
+                bin_op_simd_float_first::<Double>(this, which, left, right, dest)?;
             }
             // Used to implement _mm_min_pd and _mm_max_pd functions.
             // Note that the semantics are a bit different from Rust simd_min
@@ -534,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                bin_op_pd(this, which, left, right, dest)?;
+                bin_op_simd_float_all::<Double>(this, which, left, right, dest)?;
             }
             // Used to implement _mm_sqrt_sd functions.
             // Performs the operations on the first component of `op` and
@@ -593,7 +582,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "llvm.x86.sse2.cmp.sd",
                 )?);
 
-                bin_op_sd(this, which, left, right, dest)?;
+                bin_op_simd_float_first::<Double>(this, which, left, right, dest)?;
             }
             // Used to implement the _mm_cmp*_pd functions.
             // Performs a comparison operation on each component of `left`
@@ -608,7 +597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "llvm.x86.sse2.cmp.pd",
                 )?);
 
-                bin_op_pd(this, which, left, right, dest)?;
+                bin_op_simd_float_all::<Double>(this, which, left, right, dest)?;
             }
             // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_sd functions.
             // Compares the first component of `left` and `right` and returns
@@ -641,52 +630,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 };
                 this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?;
             }
-            // Used to implement the _mm_cvtpd_ps function.
-            // Converts packed f32 to packed f64.
-            "cvtpd2ps" => {
+            // Used to implement the _mm_cvtpd_ps and _mm_cvtps_pd functions.
+            // Converts packed f32/f64 to packed f64/f32.
+            "cvtpd2ps" | "cvtps2pd" => {
                 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 f32x4
-                assert_eq!(op_len, 2);
-                assert_eq!(dest_len, 4);
-
-                for i in 0..op_len {
-                    let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f64()?;
+                // For cvtpd2ps: op is f64x2, dest is f32x4
+                // For cvtps2pd: op is f32x4, dest is f64x2
+                // In either case, the two first values are converted
+                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 = op.convert(/*loses_info*/ &mut false).value;
-                    this.write_scalar(Scalar::from_f32(res), &dest)?;
+                    let res = this.float_to_float_or_int(&op, dest.layout.ty)?;
+                    this.write_immediate(res, &dest)?;
                 }
-                // Fill the remaining with zeros
+                // For f32 -> f64, ignore the remaining
+                // For f64 -> f32, fill the remaining with zeros
                 for i in op_len..dest_len {
                     let dest = this.project_index(&dest, i)?;
-                    this.write_scalar(Scalar::from_u32(0), &dest)?;
+                    this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
                 }
             }
-            // Used to implement the _mm_cvtps_pd function.
-            // Converts packed f64 to packed f32.
-            "cvtps2pd" => {
-                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 f32x4, dest is f64x2
-                assert_eq!(op_len, 4);
-                assert_eq!(dest_len, 2);
-
-                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 = op.convert(/*loses_info*/ &mut false).value;
-                    this.write_scalar(Scalar::from_f64(res), &dest)?;
-                }
-                // the two remaining f32 are ignored
-            }
             // Used to implement the _mm_cvtpd_epi32 and _mm_cvttpd_epi32 functions.
             // Converts packed f64 to packed i32.
             "cvtpd2dq" | "cvttpd2dq" => {
@@ -726,34 +694,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.write_scalar(Scalar::from_i32(0), &dest)?;
                 }
             }
-            // Use to implement the _mm_cvtsd_si32 and _mm_cvttsd_si32 functions.
-            // Converts the first component of `op` from f64 to i32.
-            "cvtsd2si" | "cvttsd2si" => {
-                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 rnd = match unprefixed_name {
-                    // "current SSE rounding mode", assume nearest
-                    // https://www.felixcloutier.com/x86/cvtsd2si
-                    "cvtsd2si" => rustc_apfloat::Round::NearestTiesToEven,
-                    // always truncate
-                    // https://www.felixcloutier.com/x86/cvttsd2si
-                    "cvttsd2si" => rustc_apfloat::Round::TowardZero,
-                    _ => unreachable!(),
-                };
-
-                let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
-                    // Fallback to minimum acording to SSE semantics.
-                    Scalar::from_i32(i32::MIN)
-                });
-
-                this.write_scalar(res, dest)?;
-            }
-            // Use to implement the _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
-            // Converts the first component of `op` from f64 to i64.
-            "cvtsd2si64" | "cvttsd2si64" => {
+            // 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.
+            "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => {
                 let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let (op, _) = this.operand_to_simd(op)?;
 
@@ -762,16 +706,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
                     // https://www.felixcloutier.com/x86/cvtsd2si
-                    "cvtsd2si64" => rustc_apfloat::Round::NearestTiesToEven,
+                    "cvtsd2si" | "cvtsd2si64" => rustc_apfloat::Round::NearestTiesToEven,
                     // always truncate
                     // https://www.felixcloutier.com/x86/cvttsd2si
-                    "cvttsd2si64" => rustc_apfloat::Round::TowardZero,
+                    "cvttsd2si" | "cvttsd2si64" => rustc_apfloat::Round::TowardZero,
                     _ => unreachable!(),
                 };
 
                 let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| {
                     // Fallback to minimum acording to SSE semantics.
-                    Scalar::from_i64(i64::MIN)
+                    Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size)
                 });
 
                 this.write_scalar(res, dest)?;
@@ -844,139 +788,3 @@ fn extract_first_u64<'tcx>(
     // Get the first u64 from the array
     this.read_scalar(&this.project_index(&op, 0)?)?.to_u64()
 }
-
-#[derive(Copy, Clone)]
-enum FloatBinOp {
-    /// Comparison
-    Cmp(FloatCmpOp),
-    /// Minimum value (with SSE semantics)
-    ///
-    /// <https://www.felixcloutier.com/x86/minsd>
-    /// <https://www.felixcloutier.com/x86/minpd>
-    Min,
-    /// Maximum value (with SSE semantics)
-    ///
-    /// <https://www.felixcloutier.com/x86/maxsd>
-    /// <https://www.felixcloutier.com/x86/maxpd>
-    Max,
-}
-
-/// Performs `which` scalar operation on `left` and `right` and returns
-/// the result.
-// FIXME make this generic over apfloat type to reduce code duplicaton with bin_op_f32
-fn bin_op_f64<'tcx>(
-    which: FloatBinOp,
-    left: &ImmTy<'tcx, Provenance>,
-    right: &ImmTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, Scalar<Provenance>> {
-    match which {
-        FloatBinOp::Cmp(which) => {
-            let left = left.to_scalar().to_f64()?;
-            let right = right.to_scalar().to_f64()?;
-            // FIXME: Make sure that these operations match the semantics of cmppd
-            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(),
-            };
-            Ok(Scalar::from_u64(if res { u64::MAX } else { 0 }))
-        }
-        FloatBinOp::Min => {
-            let left = left.to_scalar().to_f64()?;
-            let right = right.to_scalar().to_f64()?;
-            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
-            // is true when `x` is either +0 or -0.
-            if (left == Double::ZERO && right == Double::ZERO)
-                || left.is_nan()
-                || right.is_nan()
-                || left >= right
-            {
-                Ok(Scalar::from_f64(right))
-            } else {
-                Ok(Scalar::from_f64(left))
-            }
-        }
-        FloatBinOp::Max => {
-            let left = left.to_scalar().to_f64()?;
-            let right = right.to_scalar().to_f64()?;
-            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
-            // is true when `x` is either +0 or -0.
-            if (left == Double::ZERO && right == Double::ZERO)
-                || left.is_nan()
-                || right.is_nan()
-                || left <= right
-            {
-                Ok(Scalar::from_f64(right))
-            } else {
-                Ok(Scalar::from_f64(left))
-            }
-        }
-    }
-}
-
-/// Performs `which` operation on the first component of `left` and `right`
-/// and copies the other components from `left`. The result is stored in `dest`.
-fn bin_op_sd<'tcx>(
-    this: &mut crate::MiriInterpCx<'_, 'tcx>,
-    which: FloatBinOp,
-    left: &OpTy<'tcx, Provenance>,
-    right: &OpTy<'tcx, Provenance>,
-    dest: &PlaceTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, ()> {
-    let (left, left_len) = this.operand_to_simd(left)?;
-    let (right, right_len) = this.operand_to_simd(right)?;
-    let (dest, dest_len) = this.place_to_simd(dest)?;
-
-    assert_eq!(dest_len, left_len);
-    assert_eq!(dest_len, right_len);
-
-    let res0 = bin_op_f64(
-        which,
-        &this.read_immediate(&this.project_index(&left, 0)?)?,
-        &this.read_immediate(&this.project_index(&right, 0)?)?,
-    )?;
-    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
-
-    for i in 1..dest_len {
-        this.copy_op(
-            &this.project_index(&left, i)?,
-            &this.project_index(&dest, i)?,
-            /*allow_transmute*/ false,
-        )?;
-    }
-
-    Ok(())
-}
-
-/// Performs `which` operation on each component of `left` and
-/// `right`, storing the result is stored in `dest`.
-fn bin_op_pd<'tcx>(
-    this: &mut crate::MiriInterpCx<'_, 'tcx>,
-    which: FloatBinOp,
-    left: &OpTy<'tcx, Provenance>,
-    right: &OpTy<'tcx, Provenance>,
-    dest: &PlaceTy<'tcx, Provenance>,
-) -> InterpResult<'tcx, ()> {
-    let (left, left_len) = this.operand_to_simd(left)?;
-    let (right, right_len) = this.operand_to_simd(right)?;
-    let (dest, dest_len) = this.place_to_simd(dest)?;
-
-    assert_eq!(dest_len, left_len);
-    assert_eq!(dest_len, right_len);
-
-    for i in 0..dest_len {
-        let left = this.read_immediate(&this.project_index(&left, i)?)?;
-        let right = this.read_immediate(&this.project_index(&right, i)?)?;
-        let dest = this.project_index(&dest, i)?;
-
-        let res = bin_op_f64(which, &left, &right)?;
-        this.write_scalar(res, &dest)?;
-    }
-
-    Ok(())
-}
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 416517d15f5..c7e6dd3615e 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -23,7 +23,9 @@ function contentToDiffLine(key, value) {
 }
 
 function shouldIgnoreField(fieldName) {
-    return fieldName === "query" || fieldName === "correction";
+    return fieldName === "query" || fieldName === "correction" ||
+        fieldName === "proposeCorrectionFrom" ||
+        fieldName === "proposeCorrectionTo";
 }
 
 // This function is only called when no matching result was found and therefore will only display
diff --git a/src/tools/rustdoc-themes/main.rs b/src/tools/rustdoc-themes/main.rs
index cc13df1f5ba..1eba83a8057 100644
--- a/src/tools/rustdoc-themes/main.rs
+++ b/src/tools/rustdoc-themes/main.rs
@@ -1,5 +1,5 @@
 use std::env::args;
-use std::fs::File;
+use std::fs::{create_dir_all, File};
 use std::io::{BufRead, BufReader, BufWriter, Write};
 use std::path::Path;
 use std::process::{exit, Command};
@@ -14,6 +14,7 @@ fn get_themes<P: AsRef<Path>>(style_path: P) -> Vec<String> {
         std::time::SystemTime::UNIX_EPOCH.elapsed().expect("time is after UNIX epoch").as_millis();
 
     let mut in_theme = None;
+    create_dir_all("build/tmp").expect("failed to create temporary test directory");
     for line in BufReader::new(File::open(style_path).expect("read rustdoc.css failed")).lines() {
         let line = line.expect("read line from rustdoc.css failed");
         let line = line.trim();
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 410852b6a31..843ffe2c4c3 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -120,7 +120,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "annotate-snippets",
     "ar_archive_writer",
     "arrayvec",
-    "atty",
     "autocfg",
     "bitflags",
     "block-buffer",
@@ -181,6 +180,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "intl-memoizer",
     "intl_pluralrules",
     "io-lifetimes",
+    "is-terminal",
     "itertools",
     "itoa",
     "jobserver",