diff options
| author | bors <bors@rust-lang.org> | 2023-09-21 08:01:45 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-09-21 08:01:45 +0000 |
| commit | d2db689e1efa5b3fff6b664b6d2dba0ef65b80e7 (patch) | |
| tree | e947a059c42ff87214337cc3a825e0b338af394d /src/tools | |
| parent | 70f3d3e6ad6656546f79fac961ed3a4316003fa3 (diff) | |
| parent | ed8fbcb05910f4439ec572bd163cc99a3603e378 (diff) | |
| download | rust-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.rs | 2 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/ty.rs | 2 | ||||
| -rw-r--r-- | src/tools/compiletest/src/common.rs | 20 | ||||
| -rw-r--r-- | src/tools/compiletest/src/header/needs.rs | 28 | ||||
| -rw-r--r-- | src/tools/compiletest/src/header/tests.rs | 234 | ||||
| -rw-r--r-- | src/tools/compiletest/src/runtest.rs | 19 | ||||
| -rw-r--r-- | src/tools/compiletest/src/util.rs | 102 | ||||
| -rw-r--r-- | src/tools/miri/Cargo.lock | 88 | ||||
| -rw-r--r-- | src/tools/miri/Cargo.toml | 2 | ||||
| -rw-r--r-- | src/tools/miri/rust-version | 2 | ||||
| -rw-r--r-- | src/tools/miri/src/helpers.rs | 37 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/backtrace.rs | 5 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/intrinsics/simd.rs | 19 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/x86/mod.rs | 158 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/x86/sse.rs | 248 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/x86/sse2.rs | 380 | ||||
| -rw-r--r-- | src/tools/rustdoc-js/tester.js | 4 | ||||
| -rw-r--r-- | src/tools/rustdoc-themes/main.rs | 3 | ||||
| -rw-r--r-- | src/tools/tidy/src/deps.rs | 2 |
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", |
