diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 4c1b791dbacb8..65d91ffc9ef15 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -232,7 +232,7 @@ jobs: - name: Install nightly toolchain run: rustup toolchain install nightly --profile minimal - name: Install rustup-toolchain-install-master - run: cargo install -f rustup-toolchain-install-master + run: cargo install --locked -f rustup-toolchain-install-master # Create a token for the next step so it can create a PR that actually runs CI. - uses: actions/create-github-app-token@v3 id: app-token diff --git a/src/tools/miri/.github/workflows/setup/action.yml b/src/tools/miri/.github/workflows/setup/action.yml index a6c591154a94d..cc00ec71a644f 100644 --- a/src/tools/miri/.github/workflows/setup/action.yml +++ b/src/tools/miri/.github/workflows/setup/action.yml @@ -38,7 +38,7 @@ runs: - name: Install the tools we need if: steps.cache.outputs.cache-hit != 'true' - run: cargo install -f rustup-toolchain-install-master hyperfine + run: cargo install --locked -f rustup-toolchain-install-master hyperfine shell: bash - name: Install "master" toolchain diff --git a/src/tools/miri/.github/workflows/sysroots.yml b/src/tools/miri/.github/workflows/sysroots.yml index a488e480c0c58..a8a9306a50ff9 100644 --- a/src/tools/miri/.github/workflows/sysroots.yml +++ b/src/tools/miri/.github/workflows/sysroots.yml @@ -20,7 +20,7 @@ jobs: - name: Build the sysroots run: | rustup toolchain install nightly - cargo install -f rustup-toolchain-install-master + cargo install --locked -f rustup-toolchain-install-master ./miri toolchain -c rust-docs # Docs are the only place targets are separated by tier ./miri install python3 -m pip install beautifulsoup4 diff --git a/src/tools/miri/.gitpod.yml b/src/tools/miri/.gitpod.yml index 724cf26df2b9b..507fbff56733f 100644 --- a/src/tools/miri/.gitpod.yml +++ b/src/tools/miri/.gitpod.yml @@ -3,7 +3,7 @@ image: ubuntu:latest tasks: - before: echo "..." init: | - cargo install rustup-toolchain-install-master + cargo install --locked rustup-toolchain-install-master ./miri toolchain ./miri build command: echo "Run tests with ./miri test" diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 4524f79456612..0a330cdd45537 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -252,7 +252,7 @@ and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`). Miri comes with a few benchmarks; you can run `./miri bench` to run them with the locally built Miri. Note: this will run `./miri install` as a side-effect. Also requires `hyperfine` to be -installed (`cargo install hyperfine`). +installed (`cargo install --locked hyperfine`). To compare the benchmark results with a baseline, do the following: - Before applying your changes, run `./miri bench --save-baseline=baseline.json`. diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 3775531a3f16d..166d45491242c 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -180,9 +180,9 @@ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", "cpufeatures", diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 2eb9ababffc8b..66971d5fa7ccc 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -648,6 +648,7 @@ Definite bugs found: * [`VecDeque::splice` confusing physical and logical indices](https://github.com/rust-lang/rust/issues/151758) * [Data race in `oneshot` channel](https://github.com/faern/oneshot/issues/69) * [Memory leak in serde-yaml-bw](https://github.com/bourumir-wyngs/serde-yaml-bw/issues/197) +* [Incorrect use of SSE4.1 intrinsic in SSE2 backend in chacha20](https://github.com/RustCrypto/stream-ciphers/issues/579) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 50a0f671aca4d..15ddc19aefffd 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -606,13 +606,17 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner // We need to remove `--error-format` as cargo specifies that to be JSON, // but when we run here, cargo does not interpret the JSON any more. `--json` // then also needs to be dropped. - for arg in &info.args { + // We also need to remove `--force-warn=unused_crate_dependencies` as cargo is not there to + // process the output. + for arg in info.args { if let Some(suffix) = arg.strip_prefix("--error-format") { assert!(suffix.starts_with('=')); // Drop this argument. } else if let Some(suffix) = arg.strip_prefix("--json") { assert!(suffix.starts_with('=')); // Drop this argument. + } else if arg == "--force-warn=unused_crate_dependencies" { + // Drop this argument. } else { cmd.arg(arg); } diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 0a372dfbf0c6d..e8fdcd80f8ddb 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -158,7 +158,7 @@ impl Command { cmd!(sh, "rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy {flags...} -- {new_commit}") .run() - .context("Failed to run rustup-toolchain-install-master. If it is not installed, run 'cargo install rustup-toolchain-install-master'.")?; + .context("Failed to run rustup-toolchain-install-master. If it is not installed, run 'cargo install --locked rustup-toolchain-install-master'.")?; cmd!(sh, "rustup override set miri").run()?; // Cleanup. cmd!(sh, "cargo clean").run()?; diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 1f775b7c771f8..0e85574e7b0ec 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9bb55c8c865411b7d9dea6ff743e583d510d89f5 +0ed41eb4142dda2df61eb1145a312c1a9d62eb56 diff --git a/src/tools/miri/src/concurrency/genmc/helper.rs b/src/tools/miri/src/concurrency/genmc/helper.rs index 34314c84db4bc..87daa05bd224c 100644 --- a/src/tools/miri/src/concurrency/genmc/helper.rs +++ b/src/tools/miri/src/concurrency/genmc/helper.rs @@ -40,15 +40,14 @@ pub fn scalar_to_genmc_scalar<'tcx>( let value: u64 = scalar_int.to_uint(scalar_int.size()).try_into().unwrap(); GenmcScalar { value, provenance: 0, is_init: true } } - rustc_const_eval::interpret::Scalar::Ptr(pointer, size) => { + rustc_const_eval::interpret::Scalar::Ptr(pointer, _ptr_size) => { // FIXME(genmc,borrow tracking): Borrow tracking information is lost. let addr = crate::Pointer::from(pointer).addr(); if let crate::Provenance::Wildcard = pointer.provenance { throw_unsup_format!("Pointers with wildcard provenance not allowed in GenMC mode"); } let (alloc_id, _size, _prov_extra) = - rustc_const_eval::interpret::Machine::ptr_get_alloc(ecx, pointer, size.into()) - .unwrap(); + rustc_const_eval::interpret::Machine::ptr_get_alloc(ecx, pointer, 0).unwrap(); let base_addr = ecx.addr_from_alloc_id(alloc_id, None)?; // Add the base_addr alloc_id pair to the map. genmc_ctx.exec_state.genmc_shared_allocs_map.borrow_mut().insert(base_addr, alloc_id); diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index 637c8b089a9ea..d60959ea73835 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -252,6 +252,41 @@ pub(crate) fn compute_crc32(crc: u32, data: u64, bit_size: u32, polynomial: u128 u32::try_from(dividend).unwrap().reverse_bits() } +/// AES primitives +pub(crate) mod aes { + /// AES S-box + /// + /// Source: [NIST Advanced Encryption Standar][1], Figure 7 (page 16) + /// + /// [1]: https://tsapps.nist.gov/publication/get_pdf.cfm?pub_id=901427 + const SBOX: [u8; 256] = [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, + 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, + 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, + 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, + 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, + 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, + 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, + 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, + 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, + 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, + 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, + 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, + 0x16, + ]; + + /// Applies S-box substitution to each byte of a 32-bit word + pub(crate) fn sub_word(word: u32) -> u32 { + let bytes = word.to_ne_bytes().map(|b| SBOX[usize::from(b)]); + u32::from_ne_bytes(bytes) + } +} + // sha256 primitives shared by the x86 and aarch64 intrinsics. Math helpers adapted from RustCrypto soft impl: // https://github.com/RustCrypto/hashes/blob/3d2bc57db40fd6aeb25d6c6da98d67e2784c2985/sha2/src/sha256/soft/compact.rs pub(crate) mod sha256 { diff --git a/src/tools/miri/src/intrinsics/x86/aesni.rs b/src/tools/miri/src/intrinsics/x86/aesni.rs index 4cb3b0c98757b..d36261ca5b87a 100644 --- a/src/tools/miri/src/intrinsics/x86/aesni.rs +++ b/src/tools/miri/src/intrinsics/x86/aesni.rs @@ -110,8 +110,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u128(u128::from_le_bytes(state.into())), &dest)?; } - // TODO: Implement the `llvm.x86.aesni.aeskeygenassist` when possible - // with an external crate. + // Used to implement the _mm_aeskeygenassist_si128 function. + // Assists in expanding the AES cipher key. + "aeskeygenassist" => { + let [ckey, rcon] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + // Transmute `__m128i` to `u128`. + let ckey = ckey.transmute(this.machine.layouts.u128, this)?; + let dest = dest.transmute(this.machine.layouts.u128, this)?; + + let rcon = this.read_scalar(rcon)?.to_u8()?; + let ckey = this.read_scalar(&ckey)?.to_u128()?; + + let res = aeskeygenassist(ckey, rcon); + + this.write_scalar(Scalar::from_u128(res), &dest)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) @@ -152,3 +165,36 @@ fn aes_round<'tcx>( interp_ok(()) } + +/// AES Key Generation Assist +/// +/// From [Intel Intrinsics Guide][1]: +/// ```text +/// X3[31:0] := a[127:96] +/// X2[31:0] := a[95:64] +/// X1[31:0] := a[63:32] +/// X0[31:0] := a[31:0] +/// RCON[31:0] := ZeroExtend32(imm8[7:0]) +/// dst[31:0] := SubWord(X1) +/// dst[63:32] := RotWord(SubWord(X1)) XOR RCON +/// dst[95:64] := SubWord(X3) +/// dst[127:96] := RotWord(SubWord(X3)) XOR RCON +/// ``` +/// +/// [1]: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128 +#[expect(clippy::as_conversions, reason = "deliberately truncating")] +fn aeskeygenassist(a: u128, rcon: u8) -> u128 { + use crate::intrinsics::math::aes::sub_word; + + let rcon = u32::from(rcon); + // TODO: use `truncate` method on stabilization + let x1 = (a >> 32) as u32; + let x3 = (a >> 96) as u32; + + let x0 = sub_word(x1); + let x1 = x0.rotate_right(8) ^ rcon; + let x2 = sub_word(x3); + let x3 = x2.rotate_right(8) ^ rcon; + + (u128::from(x3) << 96) | (u128::from(x2) << 64) | (u128::from(x1) << 32) | u128::from(x0) +} diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 9eaadffb55922..aebe0a4d2c836 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -317,10 +317,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { name if name == this.mangle_internal_symbol(NO_ALLOC_SHIM_IS_UNSTABLE) => { // This is a no-op shim that only exists to prevent making the allocator shims // instantly stable. - let [] = this.check_shim_sig( - shim_sig!(extern "Rust" fn() -> ()), - (link_name, abi, args), - )?; + let [] = this + .check_shim_sig(shim_sig!(extern "Rust" fn() -> ()), (link_name, abi, args))?; } // Miri-specific extern functions diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 4c9436771a21e..5e8d6ef34327b 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -828,7 +828,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { shim_sig!(extern "system" fn(winapi::HMODULE, *_) -> winapi::FARPROC), (link_name, abi, args), )?; - this.read_target_isize(module)?; + this.read_target_isize(module)?; // FIXME validate the module! let name = this.read_c_str(this.read_pointer(proc_name)?)?; if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) diff --git a/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml b/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml index f1dc4acb6dff6..7aa787776d197 100644 --- a/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml +++ b/src/tools/miri/test-cargo-miri/proc-macro-crate/Cargo.toml @@ -10,3 +10,6 @@ proc-macro = true [dependencies] # A common dependency of proc macros, let's make sure that works. proc-macro2 = "1.0" + +[lints.cargo] +unused_dependencies = "allow" diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 703077e303a6b..8eee645dce69c 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -158,7 +158,7 @@ where /// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. /// Doesn't make a big difference when running this in Miri, but it means we can compare this -/// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. +/// with the LLVM backend by running `rustc -Zmir-opt-level=0`. #[track_caller] #[inline(never)] fn assert_eq(x: T, y: T) { diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index eac901e7c5a56..c16bc21636f78 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -16,7 +16,7 @@ #![cfg_attr(not(miri), allow(unused))] use std::fmt::{self, Debug, Formatter}; -use std::intrinsics::simd as intrinsics; +use std::intrinsics::simd::*; use std::ptr; use std::simd::StdFloat; use std::simd::prelude::*; @@ -31,7 +31,7 @@ macro_rules! assert_eq { }} } -// The `portable_simd` crate currently does not support f16 or f128 vectors, so we define our own. +// The `portable_simd` crate currently does not support f128 vectors, so we define our own. #[repr(simd, packed)] #[derive(Copy)] struct PackedSimd([T; N]); @@ -54,10 +54,6 @@ impl Debug for PackedSimd { } } -type f16x2 = PackedSimd; -type f16x4 = PackedSimd; -type f16x8 = PackedSimd; - type f128x2 = PackedSimd; type f128x4 = PackedSimd; @@ -79,95 +75,81 @@ impl PackedSimd { pub const unsafe fn simd_shuffle_const_generic(x: T, y: T) -> U; #[cfg(any(miri, target_has_reliable_f16_math))] -fn simd_ops_f16() { - use intrinsics::*; - +fn test_simd_ops_f16() { let a = f16x4::splat(10.0); let b = f16x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f16x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f16x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f16x4::from_array([9.0, 8.0, 7.0, 14.0])); + assert_eq!(a * b, f16x4::from_array([10.0, 20.0, 30.0, -40.0])); + assert_eq!(b / a, f16x4::from_array([0.1, 0.2, 0.3, -0.4])); + assert_eq!(a / f16x4::splat(2.0), f16x4::splat(5.0)); + assert_eq!(a % b, f16x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f16x4::from_array([1.0, 2.0, 3.0, 4.0])); + assert_eq!(a.simd_max(b * f16x4::splat(4.0)), f16x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.simd_min(b * f16x4::splat(4.0)), f16x4::from_array([4.0, 8.0, 10.0, -16.0])); - unsafe { - assert_eq!(simd_neg(b), f16x4::from_array([-1.0, -2.0, -3.0, 4.0])); - assert_eq!(simd_add(a, b), f16x4::from_array([11.0, 12.0, 13.0, 6.0])); - assert_eq!(simd_sub(a, b), f16x4::from_array([9.0, 8.0, 7.0, 14.0])); - assert_eq!(simd_mul(a, b), f16x4::from_array([10.0, 20.0, 30.0, -40.0])); - assert_eq!(simd_div(b, a), f16x4::from_array([0.1, 0.2, 0.3, -0.4])); - assert_eq!(simd_div(a, f16x4::splat(2.0)), f16x4::splat(5.0)); - assert_eq!(simd_rem(a, b), f16x4::from_array([0.0, 0.0, 1.0, 2.0])); - assert_eq!(simd_fabs(b), f16x4::from_array([1.0, 2.0, 3.0, 4.0])); - assert_eq!( - simd_maximum_number_nsz(a, simd_mul(b, f16x4::splat(4.0))), - f16x4::from_array([10.0, 10.0, 12.0, 10.0]) - ); - assert_eq!( - simd_minimum_number_nsz(a, simd_mul(b, f16x4::splat(4.0))), - f16x4::from_array([4.0, 8.0, 10.0, -16.0]) - ); - - assert_eq!(simd_fma(a, b, a), simd_add(simd_mul(a, b), a)); - assert_eq!(simd_fma(b, b, a), simd_add(simd_mul(b, b), a)); - assert_eq!(simd_fma(a, b, b), simd_add(simd_mul(a, b), b)); - assert_eq!( - simd_fma(f16x4::splat(-3.2), b, f16x4::splat(f16::NEG_INFINITY)), - f16x4::splat(f16::NEG_INFINITY) - ); + assert_eq!(a.mul_add(b, a), (a * b) + a); + assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!(a.mul_add(b, b), (a * b) + b); + assert_eq!( + f16x4::splat(-3.2).mul_add(b, f16x4::splat(f16::NEG_INFINITY)), + f16x4::splat(f16::NEG_INFINITY) + ); - assert_eq!(simd_relaxed_fma(a, b, a), simd_add(simd_mul(a, b), a)); - assert_eq!(simd_relaxed_fma(b, b, a), simd_add(simd_mul(b, b), a)); - assert_eq!(simd_relaxed_fma(a, b, b), simd_add(simd_mul(a, b), b)); + // All intermediate values can be precisely represented so even relaxed FMA are deterministic. + unsafe { + assert_eq!(simd_relaxed_fma(a, b, a), (a * b) + a); + assert_eq!(simd_relaxed_fma(b, b, a), (b * b) + a); + assert_eq!(simd_relaxed_fma(a, b, b), (a * b) + b); assert_eq!( simd_relaxed_fma(f16x4::splat(-3.2), b, f16x4::splat(f16::NEG_INFINITY)), f16x4::splat(f16::NEG_INFINITY) ); + } - assert_eq!(simd_fsqrt(simd_mul(a, a)), a); - assert_eq!(simd_fsqrt(simd_mul(b, b)), simd_fabs(b)); + assert_eq!((a * a).sqrt(), a); + assert_eq!((b * b).sqrt(), b.abs()); - assert_eq!(simd_eq(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([0, !0, 0, 0])); - assert_eq!(simd_ne(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([!0, 0, !0, !0])); - assert_eq!(simd_le(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([0, !0, !0, 0])); - assert_eq!(simd_lt(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([0, 0, !0, 0])); - assert_eq!(simd_ge(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([!0, !0, 0, !0])); - assert_eq!(simd_gt(a, simd_mul(f16x4::splat(5.0), b)), i32x4::from_array([!0, 0, 0, !0])); + assert_eq!(a.simd_eq(f16x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(f16x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(f16x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(f16x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(f16x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(f16x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); - assert_eq!(simd_reduce_add_ordered(a, 0.0), 40.0f16); - assert_eq!(simd_reduce_add_ordered(b, 0.0), 2.0f16); - assert_eq!(simd_reduce_mul_ordered(a, 1.0), 10000.0f16); - assert_eq!(simd_reduce_mul_ordered(b, 1.0), -24.0f16); + assert_eq!(a.reduce_sum(), 40.0); + assert_eq!(b.reduce_sum(), 2.0); + assert_eq!(a.reduce_product(), 100.0 * 100.0); + assert_eq!(b.reduce_product(), -24.0); - assert_eq!( - simd_maximum_number_nsz( - f16x2::from_array([0.0, f16::NAN]), - f16x2::from_array([f16::NAN, 0.0]) - ), - f16x2::from_array([0.0, 0.0]) - ); - assert_eq!( - simd_minimum_number_nsz( - f16x2::from_array([0.0, f16::NAN]), - f16x2::from_array([f16::NAN, 0.0]) - ), - f16x2::from_array([0.0, 0.0]) - ); + assert_eq!( + f16x2::from_array([0.0, f16::NAN]).simd_max(f16x2::from_array([f16::NAN, 0.0])), + f16x2::from_array([0.0, 0.0]) + ); + assert_eq!( + f16x2::from_array([0.0, f16::NAN]).simd_min(f16x2::from_array([f16::NAN, 0.0])), + f16x2::from_array([0.0, 0.0]) + ); - // FIXME(llvm): The LLVM backend rejects float `simd_reduce_{min,max}`, - // see https://github.com/llvm/llvm-project/issues/185827. - #[cfg(miri)] - { - assert_eq!(simd_reduce_max(a), 10.0f16); - assert_eq!(simd_reduce_max(b), 3.0f16); - assert_eq!(simd_reduce_min(a), 10.0f16); - assert_eq!(simd_reduce_min(b), -4.0f16); + // FIXME(llvm): The LLVM backend rejects float `simd_reduce_{min,max}`, + // see https://github.com/llvm/llvm-project/issues/185827. + #[cfg(miri)] + unsafe { + assert_eq!(simd_reduce_max(a), 10.0f16); + assert_eq!(simd_reduce_max(b), 3.0f16); + assert_eq!(simd_reduce_min(a), 10.0f16); + assert_eq!(simd_reduce_min(b), -4.0f16); - assert_eq!(simd_reduce_max(f16x2::from_array([0.0, f16::NAN])), 0.0f16); - assert_eq!(simd_reduce_max(f16x2::from_array([f16::NAN, 0.0])), 0.0f16); + assert_eq!(simd_reduce_max(f16x2::from_array([0.0, f16::NAN])), 0.0f16); + assert_eq!(simd_reduce_max(f16x2::from_array([f16::NAN, 0.0])), 0.0f16); - assert_eq!(simd_reduce_min(f16x2::from_array([0.0, f16::NAN])), 0.0f16); - assert_eq!(simd_reduce_min(f16x2::from_array([f16::NAN, 0.0])), 0.0f16); - } + assert_eq!(simd_reduce_min(f16x2::from_array([0.0, f16::NAN])), 0.0f16); + assert_eq!(simd_reduce_min(f16x2::from_array([f16::NAN, 0.0])), 0.0f16); } } -fn simd_ops_f32() { +fn test_simd_ops_f32() { let a = f32x4::splat(10.0); let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); assert_eq!(-b, f32x4::from_array([-1.0, -2.0, -3.0, 4.0])); @@ -189,12 +171,13 @@ fn simd_ops_f32() { f32x4::splat(f32::NEG_INFINITY) ); + // All intermediate values can be precisely represented so even relaxed FMA are deterministic. unsafe { - assert_eq!(intrinsics::simd_relaxed_fma(a, b, a), (a * b) + a); - assert_eq!(intrinsics::simd_relaxed_fma(b, b, a), (b * b) + a); - assert_eq!(intrinsics::simd_relaxed_fma(a, b, b), (a * b) + b); + assert_eq!(simd_relaxed_fma(a, b, a), (a * b) + a); + assert_eq!(simd_relaxed_fma(b, b, a), (b * b) + a); + assert_eq!(simd_relaxed_fma(a, b, b), (a * b) + b); assert_eq!( - intrinsics::simd_relaxed_fma(f32x4::splat(-3.2), b, f32x4::splat(f32::NEG_INFINITY)), + simd_relaxed_fma(f32x4::splat(-3.2), b, f32x4::splat(f32::NEG_INFINITY)), f32x4::splat(f32::NEG_INFINITY) ); } @@ -227,8 +210,6 @@ fn simd_ops_f32() { // see https://github.com/llvm/llvm-project/issues/185827. #[cfg(miri)] unsafe { - use intrinsics::{simd_reduce_max, simd_reduce_min}; - assert_eq!(simd_reduce_max(a), 10.0f32); assert_eq!(simd_reduce_max(b), 3.0f32); assert_eq!(simd_reduce_min(a), 10.0f32); @@ -242,7 +223,7 @@ fn simd_ops_f32() { } } -fn simd_ops_f64() { +fn test_simd_ops_f64() { let a = f64x4::splat(10.0); let b = f64x4::from_array([1.0, 2.0, 3.0, -4.0]); assert_eq!(-b, f64x4::from_array([-1.0, -2.0, -3.0, 4.0])); @@ -264,12 +245,13 @@ fn simd_ops_f64() { f64x4::splat(f64::NEG_INFINITY) ); + // All intermediate values can be precisely represented so even relaxed FMA are deterministic. unsafe { - assert_eq!(intrinsics::simd_relaxed_fma(a, b, a), (a * b) + a); - assert_eq!(intrinsics::simd_relaxed_fma(b, b, a), (b * b) + a); - assert_eq!(intrinsics::simd_relaxed_fma(a, b, b), (a * b) + b); + assert_eq!(simd_relaxed_fma(a, b, a), (a * b) + a); + assert_eq!(simd_relaxed_fma(b, b, a), (b * b) + a); + assert_eq!(simd_relaxed_fma(a, b, b), (a * b) + b); assert_eq!( - intrinsics::simd_relaxed_fma(f64x4::splat(-3.2), b, f64x4::splat(f64::NEG_INFINITY)), + simd_relaxed_fma(f64x4::splat(-3.2), b, f64x4::splat(f64::NEG_INFINITY)), f64x4::splat(f64::NEG_INFINITY) ); } @@ -302,8 +284,6 @@ fn simd_ops_f64() { // see https://github.com/llvm/llvm-project/issues/185827. #[cfg(miri)] unsafe { - use intrinsics::{simd_reduce_max, simd_reduce_min}; - assert_eq!(simd_reduce_max(a), 10.0f64); assert_eq!(simd_reduce_max(b), 3.0f64); assert_eq!(simd_reduce_min(a), 10.0f64); @@ -318,9 +298,7 @@ fn simd_ops_f64() { } #[cfg(any(miri, target_has_reliable_f128_math))] -fn simd_ops_f128() { - use intrinsics::*; - +fn test_simd_ops_f128() { let a = f128x4::splat(10.0); let b = f128x4::from_array([1.0, 2.0, 3.0, -4.0]); @@ -350,6 +328,7 @@ fn simd_ops_f128() { f128x4::splat(f128::NEG_INFINITY) ); + // All intermediate values can be precisely represented so even relaxed FMA are deterministic. assert_eq!(simd_relaxed_fma(a, b, a), simd_add(simd_mul(a, b), a)); assert_eq!(simd_relaxed_fma(b, b, a), simd_add(simd_mul(b, b), a)); assert_eq!(simd_relaxed_fma(a, b, b), simd_add(simd_mul(a, b), b)); @@ -406,7 +385,7 @@ fn simd_ops_f128() { } } -fn simd_ops_i32() { +fn test_simd_ops_i32() { let a = i32x4::splat(10); let b = i32x4::from_array([1, 2, 3, -4]); assert_eq!(-b, i32x4::from_array([-1, -2, -3, 4])); @@ -517,17 +496,15 @@ fn simd_ops_i32() { let d = u32x4::splat(0x2fe78e45); unsafe { - assert_eq!(intrinsics::simd_funnel_shl(c, d, u32x4::splat(0)), c); - assert_eq!(intrinsics::simd_funnel_shl(c, d, u32x4::splat(8)), u32x4::splat(0x0000b32f)); + assert_eq!(simd_funnel_shl(c, d, u32x4::splat(0)), c); + assert_eq!(simd_funnel_shl(c, d, u32x4::splat(8)), u32x4::splat(0x0000b32f)); - assert_eq!(intrinsics::simd_funnel_shr(c, d, u32x4::splat(0)), d); - assert_eq!(intrinsics::simd_funnel_shr(c, d, u32x4::splat(8)), u32x4::splat(0xb32fe78e)); + assert_eq!(simd_funnel_shr(c, d, u32x4::splat(0)), d); + assert_eq!(simd_funnel_shr(c, d, u32x4::splat(8)), u32x4::splat(0xb32fe78e)); } } -fn simd_mask() { - use std::intrinsics::simd::*; - +fn test_simd_mask() { let intmask = Mask::from_simd(i32x4::from_array([0, -1, 0, 0])); assert_eq!(intmask, Mask::from_array([false, true, false, false])); assert_eq!(intmask.to_array(), [false, true, false, false]); @@ -705,7 +682,7 @@ fn simd_mask() { } } -fn simd_cast() { +fn test_simd_cast() { // between integer types assert_eq!(i32x4::from_array([1, 2, 3, -4]), i16x4::from_array([1, 2, 3, -4]).cast()); assert_eq!(i16x4::from_array([1, 2, 3, -4]), i32x4::from_array([1, 2, 3, -4]).cast()); @@ -783,7 +760,7 @@ fn simd_cast() { } } -fn simd_swizzle() { +fn test_simd_swizzle() { let a = f32x4::splat(10.0); let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); @@ -792,7 +769,7 @@ fn simd_swizzle() { assert_eq!(simd_swizzle!(b, a, [3, 4]), f32x2::from_array([-4.0, 10.0])); } -fn simd_swizzle_dyn() { +fn test_simd_swizzle_dyn() { if cfg!(target_arch = "loongarch64") { // We don't support the required intrinsic here. return; @@ -815,7 +792,7 @@ fn simd_swizzle_dyn() { check_swizzle_dyn::<64>(); } -fn simd_gather_scatter() { +fn test_simd_gather_scatter() { let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. @@ -831,7 +808,7 @@ fn simd_gather_scatter() { Simd::from_array([ptr::null(), ptr::addr_of!(val), ptr::addr_of!(val), ptr::addr_of!(val)]); let default = u8x4::splat(0); let mask = i8x4::from_array([0, !0, 0, !0]); - let vals = unsafe { intrinsics::simd_gather(default, ptrs, mask) }; + let vals = unsafe { simd_gather(default, ptrs, mask) }; assert_eq!(vals, u8x4::from_array([0, 42, 0, 42]),); let mut val1 = 0u8; @@ -843,7 +820,7 @@ fn simd_gather_scatter() { ptr::addr_of_mut!(val2), ]); let vals = u8x4::from_array([1, 2, 3, 4]); - unsafe { intrinsics::simd_scatter(vals, ptrs, mask) }; + unsafe { simd_scatter(vals, ptrs, mask) }; assert_eq!(val1, 2); assert_eq!(val2, 4); @@ -856,33 +833,31 @@ fn simd_gather_scatter() { ptr::addr_of_mut!(val), ]); let vals = u8x4::from_array([1, 2, 3, 4]); - unsafe { intrinsics::simd_scatter(vals, ptrs, mask) }; + unsafe { simd_scatter(vals, ptrs, mask) }; assert_eq!(val, 4); } -fn simd_round() { +fn test_simd_round() { #[cfg(any(miri, target_has_reliable_f16_math))] - unsafe { - use intrinsics::*; - + { assert_eq!( - simd_ceil(f16x4::from_array([0.9, 1.001, 2.0, -4.5])), + f16x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(), f16x4::from_array([1.0, 2.0, 2.0, -4.0]) ); assert_eq!( - simd_floor(f16x4::from_array([0.9, 1.001, 2.0, -4.5])), + f16x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(), f16x4::from_array([0.0, 1.0, 2.0, -5.0]) ); assert_eq!( - simd_round(f16x4::from_array([0.9, 1.001, 2.0, -4.5])), + f16x4::from_array([0.9, 1.001, 2.0, -4.5]).round(), f16x4::from_array([1.0, 1.0, 2.0, -5.0]) ); assert_eq!( - simd_round_ties_even(f16x4::from_array([0.9, 1.001, 2.0, -4.5])), + f16x4::from_array([0.9, 1.001, 2.0, -4.5]).round_ties_even(), f16x4::from_array([1.0, 1.0, 2.0, -4.0]) ); assert_eq!( - simd_trunc(f16x4::from_array([0.9, 1.001, 2.0, -4.5])), + f16x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(), f16x4::from_array([0.0, 1.0, 2.0, -4.0]) ); } @@ -900,7 +875,7 @@ fn simd_round() { f32x4::from_array([1.0, 1.0, 2.0, -5.0]) ); assert_eq!( - unsafe { intrinsics::simd_round_ties_even(f32x4::from_array([0.9, 1.001, 2.0, -4.5])) }, + unsafe { simd_round_ties_even(f32x4::from_array([0.9, 1.001, 2.0, -4.5])) }, f32x4::from_array([1.0, 1.0, 2.0, -4.0]) ); assert_eq!( @@ -921,7 +896,7 @@ fn simd_round() { f64x4::from_array([1.0, 1.0, 2.0, -5.0]) ); assert_eq!( - unsafe { intrinsics::simd_round_ties_even(f64x4::from_array([0.9, 1.001, 2.0, -4.5])) }, + unsafe { simd_round_ties_even(f64x4::from_array([0.9, 1.001, 2.0, -4.5])) }, f64x4::from_array([1.0, 1.0, 2.0, -4.0]) ); assert_eq!( @@ -931,8 +906,6 @@ fn simd_round() { #[cfg(any(miri, target_has_reliable_f128_math))] unsafe { - use intrinsics::*; - assert_eq!( simd_ceil(f128x4::from_array([0.9, 1.001, 2.0, -4.5])), f128x4::from_array([1.0, 2.0, 2.0, -4.0]) @@ -956,9 +929,7 @@ fn simd_round() { } } -fn simd_intrinsics() { - use intrinsics::*; - +fn test_simd_intrinsics() { unsafe { // Make sure simd_eq returns all-1 for `true` let a = i32x4::splat(10); @@ -1012,9 +983,7 @@ fn simd_intrinsics() { } } -fn simd_float_intrinsics() { - use intrinsics::*; - +fn test_simd_float_intrinsics() { // These are just smoke tests to ensure the intrinsics can be called. unsafe { let a = f16x8::splat(10.0); @@ -1058,9 +1027,7 @@ fn simd_float_intrinsics() { } } -fn simd_masked_loadstore() { - use intrinsics::*; - +fn test_simd_masked_loadstore() { // The buffer is deliberarely too short, so reading the last element would be UB. let buf = [3i32; 3]; let default = i32x4::splat(0); @@ -1148,7 +1115,7 @@ fn simd_masked_loadstore() { assert_eq!(buf, vals); } -fn simd_ops_non_pow2() { +fn test_simd_ops_non_pow2() { // Just a little smoke test for operations on non-power-of-two vectors. #[repr(simd, packed)] #[derive(Copy, Clone)] @@ -1159,31 +1126,31 @@ fn simd_ops_non_pow2() { let x = SimdPacked([1u32; 3]); let y = SimdPacked([2u32; 3]); - let z = unsafe { intrinsics::simd_add(x, y) }; + let z = unsafe { simd_add(x, y) }; assert_eq!(unsafe { *(&raw const z).cast::<[u32; 3]>() }, [3u32; 3]); let x = SimdPadded([1u32; 3]); let y = SimdPadded([2u32; 3]); - let z = unsafe { intrinsics::simd_add(x, y) }; + let z = unsafe { simd_add(x, y) }; assert_eq!(unsafe { *(&raw const z).cast::<[u32; 3]>() }, [3u32; 3]); } fn main() { - simd_mask(); + test_simd_mask(); #[cfg(any(miri, target_has_reliable_f16_math))] - simd_ops_f16(); - simd_ops_f32(); - simd_ops_f64(); + test_simd_ops_f16(); + test_simd_ops_f32(); + test_simd_ops_f64(); #[cfg(any(miri, target_has_reliable_f128_math))] - simd_ops_f128(); - simd_ops_i32(); - simd_ops_non_pow2(); - simd_cast(); - simd_swizzle(); - simd_swizzle_dyn(); - simd_gather_scatter(); - simd_round(); - simd_intrinsics(); - simd_float_intrinsics(); - simd_masked_loadstore(); + test_simd_ops_f128(); + test_simd_ops_i32(); + test_simd_ops_non_pow2(); + test_simd_cast(); + test_simd_swizzle(); + test_simd_swizzle_dyn(); + test_simd_gather_scatter(); + test_simd_round(); + test_simd_intrinsics(); + test_simd_float_intrinsics(); + test_simd_masked_loadstore(); } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index 82b0d26d4df1b..11fa75962a954 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -90,6 +90,16 @@ unsafe fn test_aes() { assert_eq_m128i(r, e); } test_mm_aesimc_si128(); + + #[target_feature(enable = "aes")] + unsafe fn test_mm_aeskeygenassist_si128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc714195.aspx. + let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); + let e = _mm_set_epi64x(0x857c266b7c266e85, 0xeac4eea9c4eeacea); + let r = _mm_aeskeygenassist_si128(a, 5); + assert_eq_m128i(r, e); + } + test_mm_aeskeygenassist_si128(); } // The constants in the tests below are just bit patterns. They should not