From 83ab57b7c42bbd7fb26a05ea11b0f21cee88894f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Wed, 28 Jan 2026 00:56:52 -0500 Subject: [PATCH 01/53] Merge commit 'd9aae8cc544c5f524a12b5f3b2f3c3745c34dd74' into sync-from-portable-simd-2026-01-28 --- .github/workflows/ci.yml | 23 +- Cargo.lock | 273 ++++++++++++---- beginners-guide.md | 2 +- crates/core_simd/examples/dot_product.rs | 34 +- crates/core_simd/examples/matrix_inversion.rs | 2 +- crates/core_simd/src/fmt.rs | 3 +- crates/core_simd/src/iter.rs | 10 +- crates/core_simd/src/lane_count.rs | 40 --- crates/core_simd/src/lib.rs | 9 +- crates/core_simd/src/masks.rs | 180 ++++++----- crates/core_simd/src/masks/bitmask.rs | 228 -------------- crates/core_simd/src/masks/full_masks.rs | 296 ------------------ crates/core_simd/src/mod.rs | 3 +- crates/core_simd/src/ops.rs | 5 +- crates/core_simd/src/ops/assign.rs | 1 - crates/core_simd/src/ops/deref.rs | 3 - crates/core_simd/src/ops/shift_scalar.rs | 10 +- crates/core_simd/src/ops/unary.rs | 4 +- crates/core_simd/src/select.rs | 189 ++++++++--- crates/core_simd/src/simd/cmp/eq.rs | 24 +- crates/core_simd/src/simd/cmp/ord.rs | 60 ++-- crates/core_simd/src/simd/num/float.rs | 10 +- crates/core_simd/src/simd/num/int.rs | 14 +- crates/core_simd/src/simd/num/uint.rs | 10 +- crates/core_simd/src/simd/ptr/const_ptr.rs | 9 +- crates/core_simd/src/simd/ptr/mut_ptr.rs | 9 +- crates/core_simd/src/swizzle.rs | 62 ++-- crates/core_simd/src/swizzle_dyn.rs | 21 +- crates/core_simd/src/to_bytes.rs | 4 +- crates/core_simd/src/vector.rs | 105 ++----- crates/core_simd/src/vendor/loongarch64.rs | 45 ++- crates/core_simd/src/vendor/wasm32.rs | 14 - crates/core_simd/src/vendor/x86.rs | 22 -- crates/core_simd/tests/masks.rs | 4 +- crates/std_float/src/lib.rs | 110 +++---- crates/std_float/tests/float.rs | 29 +- crates/test_helpers/Cargo.toml | 1 + crates/test_helpers/src/approxeq.rs | 110 +++++++ crates/test_helpers/src/lib.rs | 80 ++++- rust-toolchain.toml | 2 +- 40 files changed, 873 insertions(+), 1187 deletions(-) delete mode 100644 crates/core_simd/src/lane_count.rs delete mode 100644 crates/core_simd/src/masks/bitmask.rs delete mode 100644 crates/core_simd/src/masks/full_masks.rs create mode 100644 crates/test_helpers/src/approxeq.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3984d8f0d8d99..de7efa3552836 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: strategy: fail-fast: false matrix: - target: [x86_64-pc-windows-msvc, i686-pc-windows-msvc, i586-pc-windows-msvc, x86_64-unknown-linux-gnu] + target: [x86_64-pc-windows-msvc, i686-pc-windows-msvc, x86_64-unknown-linux-gnu] # `default` means we use the default target config for the target, # `native` means we run with `-Ctarget-cpu=native`, and anything else is # an arg to `-Ctarget-feature` @@ -68,18 +68,12 @@ jobs: exclude: # -Ctarget-cpu=native sounds like bad-news if target != host - { target: i686-pc-windows-msvc, target_feature: native } - - { target: i586-pc-windows-msvc, target_feature: native } include: # Populate the `matrix.os` field - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest } - { target: x86_64-pc-windows-msvc, os: windows-latest } - { target: i686-pc-windows-msvc, os: windows-latest } - - { target: i586-pc-windows-msvc, os: windows-latest } - - # These are globally available on all the other targets. - - { target: i586-pc-windows-msvc, target_feature: +sse, os: windows-latest } - - { target: i586-pc-windows-msvc, target_feature: +sse2, os: windows-latest } # Annoyingly, the x86_64-unknown-linux-gnu runner *almost* always has # avx512vl, but occasionally doesn't. Maybe one day we can enable it. @@ -129,7 +123,7 @@ jobs: run: cargo doc --verbose --target=${{ matrix.target }} env: RUSTDOCFLAGS: -Dwarnings - + macos-tests: name: ${{ matrix.target }} runs-on: macos-latest @@ -246,9 +240,18 @@ jobs: miri: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] env: PROPTEST_CASES: 16 steps: - uses: actions/checkout@v4 - - name: Test (Miri) - run: cargo miri test + + - name: Install cargo-nextest + uses: taiki-e/install-action@nextest + + - name: Test (Miri) (partition ${{ matrix.shard }}/4) + run: | + cargo miri nextest run --partition count:${{ matrix.shard }}/4 diff --git a/Cargo.lock b/Cargo.lock index 1584c704fb221..5a5f0d8907ae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,12 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" @@ -16,31 +16,30 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "cc" +version = "1.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" +dependencies = [ + "shlex", +] [[package]] -name = "console_error_panic_hook" -version = "0.1.7" +name = "cfg-if" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "core_simd" @@ -53,47 +52,70 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "log" -version = "0.4.20" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "minicov" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -114,9 +136,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -167,10 +189,25 @@ dependencies = [ ] [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "std_float" @@ -184,9 +221,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -197,34 +234,46 @@ dependencies = [ name = "test_helpers" version = "0.1.0" dependencies = [ + "float-cmp", "proptest", ] [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -233,21 +282,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -255,9 +305,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -268,19 +318,21 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-bindgen-test" -version = "0.3.37" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" dependencies = [ - "console_error_panic_hook", "js-sys", - "scoped-tls", + "minicov", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", @@ -288,20 +340,123 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.37" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", + "syn", ] [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/beginners-guide.md b/beginners-guide.md index dc08d847ced50..4250a18315a6e 100644 --- a/beginners-guide.md +++ b/beginners-guide.md @@ -25,7 +25,7 @@ SIMD has a few special vocabulary terms you should know: * **Scalar:** "Scalar" in mathematical contexts refers to values that can be represented as a single element, mostly numbers like 6, 3.14, or -2. It can also be used to describe "scalar operations" that use strictly scalar values, like addition. This term is mostly used to differentiate between vectorized operations that use SIMD instructions and scalar operations that don't. -* **Lane:** A single element position within a vector is called a lane. If you have `N` lanes available then they're numbered from `0` to `N-1` when referring to them, again like an array. The biggest difference between an array element and a vector lane is that in general is *relatively costly* to access an individual lane value. On most architectures, the vector has to be pushed out of the SIMD register onto the stack, then an individual lane is accessed while it's on the stack (and possibly the stack value is read back into a register). For this reason, when working with SIMD you should avoid reading or writing the value of an individual lane during hot loops. +* **Lane:** A single element position within a vector is called a lane. If you have `N` lanes available then they're numbered from `0` to `N-1` when referring to them, again like an array. The biggest difference between an array element and a vector lane is that in general it is *relatively costly* to access an individual lane value. On most architectures, the vector has to be pushed out of the SIMD register onto the stack, then an individual lane is accessed while it's on the stack (and possibly the stack value is read back into a register). For this reason, when working with SIMD you should avoid reading or writing the value of an individual lane during hot loops. * **Bit Widths:** When talking about SIMD, the bit widths used are the bit size of the vectors involved, *not* the individual elements. So "128-bit SIMD" has 128-bit vectors, and that might be `f32x4`, `i32x4`, `i16x8`, or other variations. While 128-bit SIMD is the most common, there's also 64-bit, 256-bit, and even 512-bit on the newest CPUs. diff --git a/crates/core_simd/examples/dot_product.rs b/crates/core_simd/examples/dot_product.rs index 75d152ae7f0e3..4ef32bfa60b5e 100644 --- a/crates/core_simd/examples/dot_product.rs +++ b/crates/core_simd/examples/dot_product.rs @@ -1,8 +1,6 @@ //! Code taken from the `packed_simd` crate. //! Run this code with `cargo test --example dot_product`. -#![feature(array_chunks)] -#![feature(slice_as_chunks)] // Add these imports to use the stdsimd library #![feature(portable_simd)] use core_simd::simd::prelude::*; @@ -33,7 +31,7 @@ pub fn dot_prod_scalar_1(a: &[f32], b: &[f32]) -> f32 { } // We now move on to the SIMD implementations: notice the following constructs: -// `array_chunks::<4>`: mapping this over the vector will let use construct SIMD vectors +// `as_chunks::<4>`: mapping this over the vector will let us construct SIMD vectors // `f32x4::from_array`: construct the SIMD vector from a slice // `(a * b).reduce_sum()`: Multiply both f32x4 vectors together, and then reduce them. // This approach essentially uses SIMD to produce a vector of length N/4 of all the products, @@ -42,9 +40,11 @@ pub fn dot_prod_scalar_1(a: &[f32], b: &[f32]) -> f32 { pub fn dot_prod_simd_0(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len()); // TODO handle remainder when a.len() % 4 != 0 - a.array_chunks::<4>() + a.as_chunks::<4>() + .0 + .iter() .map(|&a| f32x4::from_array(a)) - .zip(b.array_chunks::<4>().map(|&b| f32x4::from_array(b))) + .zip(b.as_chunks::<4>().0.iter().map(|&b| f32x4::from_array(b))) .map(|(a, b)| (a * b).reduce_sum()) .sum() } @@ -60,9 +60,11 @@ pub fn dot_prod_simd_0(a: &[f32], b: &[f32]) -> f32 { pub fn dot_prod_simd_1(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len()); // TODO handle remainder when a.len() % 4 != 0 - a.array_chunks::<4>() + a.as_chunks::<4>() + .0 + .iter() .map(|&a| f32x4::from_array(a)) - .zip(b.array_chunks::<4>().map(|&b| f32x4::from_array(b))) + .zip(b.as_chunks::<4>().0.iter().map(|&b| f32x4::from_array(b))) .fold(f32x4::splat(0.0), |acc, zipped| acc + zipped.0 * zipped.1) .reduce_sum() } @@ -74,9 +76,11 @@ pub fn dot_prod_simd_2(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len()); // TODO handle remainder when a.len() % 4 != 0 let mut res = f32x4::splat(0.0); - a.array_chunks::<4>() + a.as_chunks::<4>() + .0 + .iter() .map(|&a| f32x4::from_array(a)) - .zip(b.array_chunks::<4>().map(|&b| f32x4::from_array(b))) + .zip(b.as_chunks::<4>().0.iter().map(|&b| f32x4::from_array(b))) .for_each(|(a, b)| { res = a.mul_add(b, res); }); @@ -113,9 +117,11 @@ pub fn dot_prod_simd_3(a: &[f32], b: &[f32]) -> f32 { // next example. pub fn dot_prod_simd_4(a: &[f32], b: &[f32]) -> f32 { let mut sum = a - .array_chunks::<4>() + .as_chunks::<4>() + .0 + .iter() .map(|&a| f32x4::from_array(a)) - .zip(b.array_chunks::<4>().map(|&b| f32x4::from_array(b))) + .zip(b.as_chunks::<4>().0.iter().map(|&b| f32x4::from_array(b))) .map(|(a, b)| a * b) .fold(f32x4::splat(0.0), std::ops::Add::add) .reduce_sum(); @@ -131,9 +137,11 @@ pub fn dot_prod_simd_4(a: &[f32], b: &[f32]) -> f32 { // This version allocates a single `XMM` register for accumulation, and the folds don't allocate on top of that. // Notice the use of `mul_add`, which can do a multiply and an add operation ber iteration. pub fn dot_prod_simd_5(a: &[f32], b: &[f32]) -> f32 { - a.array_chunks::<4>() + a.as_chunks::<4>() + .0 + .iter() .map(|&a| f32x4::from_array(a)) - .zip(b.array_chunks::<4>().map(|&b| f32x4::from_array(b))) + .zip(b.as_chunks::<4>().0.iter().map(|&b| f32x4::from_array(b))) .fold(f32x4::splat(0.), |acc, (a, b)| a.mul_add(b, acc)) .reduce_sum() } diff --git a/crates/core_simd/examples/matrix_inversion.rs b/crates/core_simd/examples/matrix_inversion.rs index bad86414401d7..ad2eea9153e08 100644 --- a/crates/core_simd/examples/matrix_inversion.rs +++ b/crates/core_simd/examples/matrix_inversion.rs @@ -1,7 +1,7 @@ //! 4x4 matrix inverse // Code ported from the `packed_simd` crate // Run this code with `cargo test --example matrix_inversion` -#![feature(array_chunks, portable_simd)] +#![feature(portable_simd)] use core_simd::simd::prelude::*; // Gotta define our own 4x4 matrix since Rust doesn't ship multidim arrays yet :^) diff --git a/crates/core_simd/src/fmt.rs b/crates/core_simd/src/fmt.rs index 3a540f5a04908..90c520e75bb39 100644 --- a/crates/core_simd/src/fmt.rs +++ b/crates/core_simd/src/fmt.rs @@ -1,9 +1,8 @@ -use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; +use crate::simd::{Simd, SimdElement}; use core::fmt; impl fmt::Debug for Simd where - LaneCount: SupportedLaneCount, T: SimdElement + fmt::Debug, { /// A `Simd` has a debug format like the one for `[T]`: diff --git a/crates/core_simd/src/iter.rs b/crates/core_simd/src/iter.rs index b3732fd74d5f6..fdc458efeda48 100644 --- a/crates/core_simd/src/iter.rs +++ b/crates/core_simd/src/iter.rs @@ -1,4 +1,4 @@ -use crate::simd::{LaneCount, Simd, SupportedLaneCount}; +use crate::simd::Simd; use core::{ iter::{Product, Sum}, ops::{Add, Mul}, @@ -7,8 +7,6 @@ use core::{ macro_rules! impl_traits { { $type:ty } => { impl Sum for Simd<$type, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn sum>(iter: I) -> Self { @@ -17,8 +15,6 @@ macro_rules! impl_traits { } impl Product for Simd<$type, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn product>(iter: I) -> Self { @@ -27,8 +23,6 @@ macro_rules! impl_traits { } impl<'a, const N: usize> Sum<&'a Self> for Simd<$type, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn sum>(iter: I) -> Self { @@ -37,8 +31,6 @@ macro_rules! impl_traits { } impl<'a, const N: usize> Product<&'a Self> for Simd<$type, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn product>(iter: I) -> Self { diff --git a/crates/core_simd/src/lane_count.rs b/crates/core_simd/src/lane_count.rs deleted file mode 100644 index bbdfd5f5f3ed3..0000000000000 --- a/crates/core_simd/src/lane_count.rs +++ /dev/null @@ -1,40 +0,0 @@ -mod sealed { - pub trait Sealed {} -} -use sealed::Sealed; - -/// Specifies the number of lanes in a SIMD vector as a type. -pub struct LaneCount; - -impl LaneCount { - /// The number of bytes in a bitmask with this many lanes. - pub const BITMASK_LEN: usize = N.div_ceil(8); -} - -/// Statically guarantees that a lane count is marked as supported. -/// -/// This trait is *sealed*: the list of implementors below is total. -/// Users do not have the ability to mark additional `LaneCount` values as supported. -/// Only SIMD vectors with supported lane counts are constructable. -pub trait SupportedLaneCount: Sealed { - #[doc(hidden)] - type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>; -} - -impl Sealed for LaneCount {} - -macro_rules! supported_lane_count { - ($($lanes:literal),+) => { - $( - impl SupportedLaneCount for LaneCount<$lanes> { - type BitMask = [u8; ($lanes + 7) / 8]; - } - )+ - }; -} - -supported_lane_count!( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 -); diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index 717b882b64ba1..fe26d99b9194c 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -9,7 +9,8 @@ simd_ffi, staged_api, prelude_import, - ptr_metadata + ptr_metadata, + rustc_attrs )] #![cfg_attr( all( @@ -30,10 +31,6 @@ any(target_arch = "powerpc", target_arch = "powerpc64"), feature(stdarch_powerpc) )] -#![cfg_attr( - all(target_arch = "x86_64", target_feature = "avx512f"), - feature(stdarch_x86_avx512) -)] #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really #![deny( unsafe_op_in_unsafe_fn, @@ -41,7 +38,7 @@ clippy::undocumented_unsafe_blocks )] #![doc(test(attr(deny(warnings))))] -#![allow(internal_features)] +#![allow(internal_features, clippy::repr_packed_without_abi)] #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index 19d45f4d3b31a..3e2209556b66b 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -2,20 +2,33 @@ //! Types representing #![allow(non_camel_case_types)] -#[cfg_attr( - not(all(target_arch = "x86_64", target_feature = "avx512f")), - path = "masks/full_masks.rs" -)] -#[cfg_attr( - all(target_arch = "x86_64", target_feature = "avx512f"), - path = "masks/bitmask.rs" -)] -mod mask_impl; - -use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount}; +use crate::simd::{Select, Simd, SimdCast, SimdElement}; use core::cmp::Ordering; use core::{fmt, mem}; +pub(crate) trait FixEndianness { + fn fix_endianness(self) -> Self; +} + +macro_rules! impl_fix_endianness { + { $($int:ty),* } => { + $( + impl FixEndianness for $int { + #[inline(always)] + fn fix_endianness(self) -> Self { + if cfg!(target_endian = "big") { + <$int>::reverse_bits(self) + } else { + self + } + } + } + )* + } +} + +impl_fix_endianness! { u8, u16, u32, u64 } + mod sealed { use super::*; @@ -28,7 +41,6 @@ mod sealed { pub trait Sealed { fn valid(values: Simd) -> bool where - LaneCount: SupportedLaneCount, Self: SimdElement; fn eq(self, other: Self) -> bool; @@ -56,8 +68,6 @@ macro_rules! impl_element { impl Sealed for $ty { #[inline] fn valid(value: Simd) -> bool - where - LaneCount: SupportedLaneCount, { // We can't use `Simd` directly, because `Simd`'s functions call this function and // we will end up with an infinite loop. @@ -108,23 +118,19 @@ impl_element! { isize, usize } /// The layout of this type is unspecified, and may change between platforms /// and/or Rust versions, and code should not assume that it is equivalent to /// `[T; N]`. +/// +/// `N` cannot be 0 and may be at most 64. This limit may be increased in +/// the future. #[repr(transparent)] -pub struct Mask(mask_impl::Mask) +pub struct Mask(Simd) where - T: MaskElement, - LaneCount: SupportedLaneCount; + T: MaskElement; -impl Copy for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ -} +impl Copy for Mask where T: MaskElement {} impl Clone for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn clone(&self) -> Self { @@ -135,12 +141,12 @@ where impl Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { /// Constructs a mask by setting all elements to the given value. #[inline] - pub fn splat(value: bool) -> Self { - Self(mask_impl::Mask::splat(value)) + #[rustc_const_unstable(feature = "portable_simd", issue = "86656")] + pub const fn splat(value: bool) -> Self { + Self(Simd::splat(if value { T::TRUE } else { T::FALSE })) } /// Converts an array of bools to a SIMD mask. @@ -156,7 +162,7 @@ where let bytes: [u8; N] = mem::transmute_copy(&array); let bools: Simd = core::intrinsics::simd::simd_ne(Simd::from_array(bytes), Simd::splat(0u8)); - Mask::from_int_unchecked(core::intrinsics::simd::simd_cast(bools)) + Mask::from_simd_unchecked(core::intrinsics::simd::simd_cast(bools)) } } @@ -174,7 +180,7 @@ where // This would be hypothetically valid as an "in-place" transmute, // but these are "dependently-sized" types, so copy elision it is! unsafe { - let mut bytes: Simd = core::intrinsics::simd::simd_cast(self.to_int()); + let mut bytes: Simd = core::intrinsics::simd::simd_cast(self.to_simd()); bytes &= Simd::splat(1i8); mem::transmute_copy(&bytes) } @@ -187,12 +193,12 @@ where /// All elements must be either 0 or -1. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub unsafe fn from_int_unchecked(value: Simd) -> Self { + pub unsafe fn from_simd_unchecked(value: Simd) -> Self { // Safety: the caller must confirm this invariant unsafe { core::intrinsics::assume(::valid(value)); - Self(mask_impl::Mask::from_int_unchecked(value)) } + Self(value) } /// Converts a vector of integers to a mask, where 0 represents `false` and -1 @@ -203,25 +209,26 @@ where #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] #[track_caller] - pub fn from_int(value: Simd) -> Self { + pub fn from_simd(value: Simd) -> Self { assert!(T::valid(value), "all values must be either 0 or -1",); // Safety: the validity has been checked - unsafe { Self::from_int_unchecked(value) } + unsafe { Self::from_simd_unchecked(value) } } /// Converts the mask to a vector of integers, where 0 represents `false` and -1 /// represents `true`. #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - pub fn to_int(self) -> Simd { - self.0.to_int() + pub fn to_simd(self) -> Simd { + self.0 } /// Converts the mask to a mask of any other element size. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub fn cast(self) -> Mask { - Mask(self.0.convert()) + // Safety: mask elements are integers + unsafe { Mask(core::intrinsics::simd::simd_as(self.0)) } } /// Tests the value of the specified element. @@ -232,7 +239,7 @@ where #[must_use = "method returns a new bool and does not mutate the original value"] pub unsafe fn test_unchecked(&self, index: usize) -> bool { // Safety: the caller must confirm this invariant - unsafe { self.0.test_unchecked(index) } + unsafe { T::eq(*self.0.as_array().get_unchecked(index), T::TRUE) } } /// Tests the value of the specified element. @@ -243,9 +250,7 @@ where #[must_use = "method returns a new bool and does not mutate the original value"] #[track_caller] pub fn test(&self, index: usize) -> bool { - assert!(index < N, "element index out of range"); - // Safety: the element index has been checked - unsafe { self.test_unchecked(index) } + T::eq(self.0[index], T::TRUE) } /// Sets the value of the specified element. @@ -256,7 +261,7 @@ where pub unsafe fn set_unchecked(&mut self, index: usize, value: bool) { // Safety: the caller must confirm this invariant unsafe { - self.0.set_unchecked(index, value); + *self.0.as_mut_array().get_unchecked_mut(index) = if value { T::TRUE } else { T::FALSE } } } @@ -267,35 +272,65 @@ where #[inline] #[track_caller] pub fn set(&mut self, index: usize, value: bool) { - assert!(index < N, "element index out of range"); - // Safety: the element index has been checked - unsafe { - self.set_unchecked(index, value); - } + self.0[index] = if value { T::TRUE } else { T::FALSE } } /// Returns true if any element is set, or false otherwise. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub fn any(self) -> bool { - self.0.any() + // Safety: `self` is a mask vector + unsafe { core::intrinsics::simd::simd_reduce_any(self.0) } } /// Returns true if all elements are set, or false otherwise. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub fn all(self) -> bool { - self.0.all() + // Safety: `self` is a mask vector + unsafe { core::intrinsics::simd::simd_reduce_all(self.0) } } /// Creates a bitmask from a mask. /// /// Each bit is set if the corresponding element in the mask is `true`. - /// If the mask contains more than 64 elements, the bitmask is truncated to the first 64. #[inline] #[must_use = "method returns a new integer and does not mutate the original value"] pub fn to_bitmask(self) -> u64 { - self.0.to_bitmask_integer() + const { + assert!(N <= 64, "number of elements can't be greater than 64"); + } + + #[inline] + unsafe fn to_bitmask_impl( + mask: Mask, + ) -> U + where + T: MaskElement, + { + let resized = mask.resize::(false); + + // Safety: `resized` is an integer vector with length M, which must match T + let bitmask: U = unsafe { core::intrinsics::simd::simd_bitmask(resized.0) }; + + // LLVM assumes bit order should match endianness + bitmask.fix_endianness() + } + + // TODO modify simd_bitmask to zero-extend output, making this unnecessary + if N <= 8 { + // Safety: bitmask matches length + unsafe { to_bitmask_impl::(self) as u64 } + } else if N <= 16 { + // Safety: bitmask matches length + unsafe { to_bitmask_impl::(self) as u64 } + } else if N <= 32 { + // Safety: bitmask matches length + unsafe { to_bitmask_impl::(self) as u64 } + } else { + // Safety: bitmask matches length + unsafe { to_bitmask_impl::(self) } + } } /// Creates a mask from a bitmask. @@ -305,7 +340,7 @@ where #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub fn from_bitmask(bitmask: u64) -> Self { - Self(mask_impl::Mask::from_bitmask_integer(bitmask)) + Self(bitmask.select(Simd::splat(T::TRUE), Simd::splat(T::FALSE))) } /// Finds the index of the first set element. @@ -351,7 +386,7 @@ where // Safety: the input and output are integer vectors let index: Simd = unsafe { core::intrinsics::simd::simd_cast(index) }; - let masked_index = self.select(index, Self::splat(true).to_int()); + let masked_index = self.select(index, Self::splat(true).to_simd()); // Safety: the input and output are integer vectors let masked_index: Simd = @@ -376,7 +411,6 @@ where impl From<[bool; N]> for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn from(array: [bool; N]) -> Self { @@ -387,7 +421,6 @@ where impl From> for [bool; N] where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn from(vector: Mask) -> Self { @@ -398,7 +431,6 @@ where impl Default for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn default() -> Self { @@ -409,7 +441,6 @@ where impl PartialEq for Mask where T: MaskElement + PartialEq, - LaneCount: SupportedLaneCount, { #[inline] fn eq(&self, other: &Self) -> bool { @@ -420,7 +451,6 @@ where impl PartialOrd for Mask where T: MaskElement + PartialOrd, - LaneCount: SupportedLaneCount, { #[inline] fn partial_cmp(&self, other: &Self) -> Option { @@ -431,7 +461,6 @@ where impl fmt::Debug for Mask where T: MaskElement + fmt::Debug, - LaneCount: SupportedLaneCount, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -444,19 +473,18 @@ where impl core::ops::BitAnd for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] fn bitand(self, rhs: Self) -> Self { - Self(self.0 & rhs.0) + // Safety: `self` is an integer vector + unsafe { Self(core::intrinsics::simd::simd_and(self.0, rhs.0)) } } } impl core::ops::BitAnd for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] @@ -468,7 +496,6 @@ where impl core::ops::BitAnd> for bool where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Mask; #[inline] @@ -480,19 +507,18 @@ where impl core::ops::BitOr for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) + // Safety: `self` is an integer vector + unsafe { Self(core::intrinsics::simd::simd_or(self.0, rhs.0)) } } } impl core::ops::BitOr for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] @@ -504,7 +530,6 @@ where impl core::ops::BitOr> for bool where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Mask; #[inline] @@ -516,19 +541,18 @@ where impl core::ops::BitXor for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] fn bitxor(self, rhs: Self) -> Self::Output { - Self(self.0 ^ rhs.0) + // Safety: `self` is an integer vector + unsafe { Self(core::intrinsics::simd::simd_xor(self.0, rhs.0)) } } } impl core::ops::BitXor for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] @@ -540,7 +564,6 @@ where impl core::ops::BitXor> for bool where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Mask; #[inline] @@ -552,30 +575,27 @@ where impl core::ops::Not for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { type Output = Mask; #[inline] fn not(self) -> Self::Output { - Self(!self.0) + Self::splat(true) ^ self } } impl core::ops::BitAndAssign for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn bitand_assign(&mut self, rhs: Self) { - self.0 = self.0 & rhs.0; + *self = *self & rhs; } } impl core::ops::BitAndAssign for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn bitand_assign(&mut self, rhs: bool) { @@ -586,18 +606,16 @@ where impl core::ops::BitOrAssign for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn bitor_assign(&mut self, rhs: Self) { - self.0 = self.0 | rhs.0; + *self = *self | rhs; } } impl core::ops::BitOrAssign for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn bitor_assign(&mut self, rhs: bool) { @@ -608,18 +626,16 @@ where impl core::ops::BitXorAssign for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn bitxor_assign(&mut self, rhs: Self) { - self.0 = self.0 ^ rhs.0; + *self = *self ^ rhs; } } impl core::ops::BitXorAssign for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { #[inline] fn bitxor_assign(&mut self, rhs: bool) { @@ -631,8 +647,6 @@ macro_rules! impl_from { { $from:ty => $($to:ty),* } => { $( impl From> for Mask<$to, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn from(value: Mask<$from, N>) -> Self { diff --git a/crates/core_simd/src/masks/bitmask.rs b/crates/core_simd/src/masks/bitmask.rs deleted file mode 100644 index 32d37b5533926..0000000000000 --- a/crates/core_simd/src/masks/bitmask.rs +++ /dev/null @@ -1,228 +0,0 @@ -#![allow(unused_imports)] -use super::MaskElement; -use crate::simd::{LaneCount, Simd, SupportedLaneCount}; -use core::marker::PhantomData; - -/// A mask where each lane is represented by a single bit. -#[repr(transparent)] -pub(crate) struct Mask( - as SupportedLaneCount>::BitMask, - PhantomData, -) -where - T: MaskElement, - LaneCount: SupportedLaneCount; - -impl Copy for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ -} - -impl Clone for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn clone(&self) -> Self { - *self - } -} - -impl PartialEq for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0.as_ref() == other.0.as_ref() - } -} - -impl PartialOrd for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.0.as_ref().partial_cmp(other.0.as_ref()) - } -} - -impl Eq for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ -} - -impl Ord for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.as_ref().cmp(other.0.as_ref()) - } -} - -impl Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub(crate) fn splat(value: bool) -> Self { - let mut mask = as SupportedLaneCount>::BitMask::default(); - if value { - mask.as_mut().fill(u8::MAX) - } else { - mask.as_mut().fill(u8::MIN) - } - if N % 8 > 0 { - *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - N % 8); - } - Self(mask, PhantomData) - } - - #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] - pub(crate) unsafe fn test_unchecked(&self, lane: usize) -> bool { - (self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0 - } - - #[inline] - pub(crate) unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { - unsafe { - self.0.as_mut()[lane / 8] ^= ((value ^ self.test_unchecked(lane)) as u8) << (lane % 8) - } - } - - #[inline] - #[must_use = "method returns a new vector and does not mutate the original value"] - pub(crate) fn to_int(self) -> Simd { - unsafe { - core::intrinsics::simd::simd_select_bitmask( - self.0, - Simd::splat(T::TRUE), - Simd::splat(T::FALSE), - ) - } - } - - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub(crate) unsafe fn from_int_unchecked(value: Simd) -> Self { - unsafe { Self(core::intrinsics::simd::simd_bitmask(value), PhantomData) } - } - - #[inline] - pub(crate) fn to_bitmask_integer(self) -> u64 { - let mut bitmask = [0u8; 8]; - bitmask[..self.0.as_ref().len()].copy_from_slice(self.0.as_ref()); - u64::from_ne_bytes(bitmask) - } - - #[inline] - pub(crate) fn from_bitmask_integer(bitmask: u64) -> Self { - let mut bytes = as SupportedLaneCount>::BitMask::default(); - let len = bytes.as_mut().len(); - bytes - .as_mut() - .copy_from_slice(&bitmask.to_ne_bytes()[..len]); - Self(bytes, PhantomData) - } - - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub(crate) fn convert(self) -> Mask - where - U: MaskElement, - { - // Safety: bitmask layout does not depend on the element width - unsafe { core::mem::transmute_copy(&self) } - } - - #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] - pub(crate) fn any(self) -> bool { - self != Self::splat(false) - } - - #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] - pub(crate) fn all(self) -> bool { - self == Self::splat(true) - } -} - -impl core::ops::BitAnd for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, - as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, -{ - type Output = Self; - #[inline] - fn bitand(mut self, rhs: Self) -> Self { - for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) { - *l &= r; - } - self - } -} - -impl core::ops::BitOr for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, - as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, -{ - type Output = Self; - #[inline] - fn bitor(mut self, rhs: Self) -> Self { - for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) { - *l |= r; - } - self - } -} - -impl core::ops::BitXor for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - type Output = Self; - #[inline] - fn bitxor(mut self, rhs: Self) -> Self::Output { - for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) { - *l ^= r; - } - self - } -} - -impl core::ops::Not for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - type Output = Self; - #[inline] - fn not(mut self) -> Self::Output { - for x in self.0.as_mut() { - *x = !*x; - } - if N % 8 > 0 { - *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - N % 8); - } - self - } -} diff --git a/crates/core_simd/src/masks/full_masks.rs b/crates/core_simd/src/masks/full_masks.rs deleted file mode 100644 index 4e98db4070a9d..0000000000000 --- a/crates/core_simd/src/masks/full_masks.rs +++ /dev/null @@ -1,296 +0,0 @@ -//! Masks that take up full SIMD vector registers. - -use crate::simd::{LaneCount, MaskElement, Simd, SupportedLaneCount}; - -#[repr(transparent)] -pub(crate) struct Mask(Simd) -where - T: MaskElement, - LaneCount: SupportedLaneCount; - -impl Copy for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ -} - -impl Clone for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn clone(&self) -> Self { - *self - } -} - -impl PartialEq for Mask -where - T: MaskElement + PartialEq, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl PartialOrd for Mask -where - T: MaskElement + PartialOrd, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Eq for Mask -where - T: MaskElement + Eq, - LaneCount: SupportedLaneCount, -{ -} - -impl Ord for Mask -where - T: MaskElement + Ord, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -// Used for bitmask bit order workaround -pub(crate) trait ReverseBits { - // Reverse the least significant `n` bits of `self`. - // (Remaining bits must be 0.) - fn reverse_bits(self, n: usize) -> Self; -} - -macro_rules! impl_reverse_bits { - { $($int:ty),* } => { - $( - impl ReverseBits for $int { - #[inline(always)] - fn reverse_bits(self, n: usize) -> Self { - let rev = <$int>::reverse_bits(self); - let bitsize = size_of::<$int>() * 8; - if n < bitsize { - // Shift things back to the right - rev >> (bitsize - n) - } else { - rev - } - } - } - )* - } -} - -impl_reverse_bits! { u8, u16, u32, u64 } - -impl Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub(crate) fn splat(value: bool) -> Self { - Self(Simd::splat(if value { T::TRUE } else { T::FALSE })) - } - - #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] - pub(crate) unsafe fn test_unchecked(&self, lane: usize) -> bool { - T::eq(self.0[lane], T::TRUE) - } - - #[inline] - pub(crate) unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { - self.0[lane] = if value { T::TRUE } else { T::FALSE } - } - - #[inline] - #[must_use = "method returns a new vector and does not mutate the original value"] - pub(crate) fn to_int(self) -> Simd { - self.0 - } - - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub(crate) unsafe fn from_int_unchecked(value: Simd) -> Self { - Self(value) - } - - #[inline] - #[must_use = "method returns a new mask and does not mutate the original value"] - pub(crate) fn convert(self) -> Mask - where - U: MaskElement, - { - // Safety: masks are simply integer vectors of 0 and -1, and we can cast the element type. - unsafe { Mask(core::intrinsics::simd::simd_cast(self.0)) } - } - - #[inline] - unsafe fn to_bitmask_impl(self) -> U - where - LaneCount: SupportedLaneCount, - { - let resized = self.to_int().resize::(T::FALSE); - - // Safety: `resized` is an integer vector with length M, which must match T - let bitmask: U = unsafe { core::intrinsics::simd::simd_bitmask(resized) }; - - // LLVM assumes bit order should match endianness - if cfg!(target_endian = "big") { - bitmask.reverse_bits(M) - } else { - bitmask - } - } - - #[inline] - unsafe fn from_bitmask_impl(bitmask: U) -> Self - where - LaneCount: SupportedLaneCount, - { - // LLVM assumes bit order should match endianness - let bitmask = if cfg!(target_endian = "big") { - bitmask.reverse_bits(M) - } else { - bitmask - }; - - // SAFETY: `mask` is the correct bitmask type for a u64 bitmask - let mask: Simd = unsafe { - core::intrinsics::simd::simd_select_bitmask( - bitmask, - Simd::::splat(T::TRUE), - Simd::::splat(T::FALSE), - ) - }; - - // SAFETY: `mask` only contains `T::TRUE` or `T::FALSE` - unsafe { Self::from_int_unchecked(mask.resize::(T::FALSE)) } - } - - #[inline] - pub(crate) fn to_bitmask_integer(self) -> u64 { - // TODO modify simd_bitmask to zero-extend output, making this unnecessary - if N <= 8 { - // Safety: bitmask matches length - unsafe { self.to_bitmask_impl::() as u64 } - } else if N <= 16 { - // Safety: bitmask matches length - unsafe { self.to_bitmask_impl::() as u64 } - } else if N <= 32 { - // Safety: bitmask matches length - unsafe { self.to_bitmask_impl::() as u64 } - } else { - // Safety: bitmask matches length - unsafe { self.to_bitmask_impl::() } - } - } - - #[inline] - pub(crate) fn from_bitmask_integer(bitmask: u64) -> Self { - // TODO modify simd_bitmask_select to truncate input, making this unnecessary - if N <= 8 { - // Safety: bitmask matches length - unsafe { Self::from_bitmask_impl::(bitmask as u8) } - } else if N <= 16 { - // Safety: bitmask matches length - unsafe { Self::from_bitmask_impl::(bitmask as u16) } - } else if N <= 32 { - // Safety: bitmask matches length - unsafe { Self::from_bitmask_impl::(bitmask as u32) } - } else { - // Safety: bitmask matches length - unsafe { Self::from_bitmask_impl::(bitmask) } - } - } - - #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] - pub(crate) fn any(self) -> bool { - // Safety: use `self` as an integer vector - unsafe { core::intrinsics::simd::simd_reduce_any(self.to_int()) } - } - - #[inline] - #[must_use = "method returns a new bool and does not mutate the original value"] - pub(crate) fn all(self) -> bool { - // Safety: use `self` as an integer vector - unsafe { core::intrinsics::simd::simd_reduce_all(self.to_int()) } - } -} - -impl From> for Simd -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - #[inline] - fn from(value: Mask) -> Self { - value.0 - } -} - -impl core::ops::BitAnd for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - type Output = Self; - #[inline] - fn bitand(self, rhs: Self) -> Self { - // Safety: `self` is an integer vector - unsafe { Self(core::intrinsics::simd::simd_and(self.0, rhs.0)) } - } -} - -impl core::ops::BitOr for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self { - // Safety: `self` is an integer vector - unsafe { Self(core::intrinsics::simd::simd_or(self.0, rhs.0)) } - } -} - -impl core::ops::BitXor for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - type Output = Self; - #[inline] - fn bitxor(self, rhs: Self) -> Self { - // Safety: `self` is an integer vector - unsafe { Self(core::intrinsics::simd::simd_xor(self.0, rhs.0)) } - } -} - -impl core::ops::Not for Mask -where - T: MaskElement, - LaneCount: SupportedLaneCount, -{ - type Output = Self; - #[inline] - fn not(self) -> Self::Output { - Self::splat(true) ^ self - } -} diff --git a/crates/core_simd/src/mod.rs b/crates/core_simd/src/mod.rs index 45b1a0f975141..5f635d80a178f 100644 --- a/crates/core_simd/src/mod.rs +++ b/crates/core_simd/src/mod.rs @@ -5,7 +5,6 @@ mod alias; mod cast; mod fmt; mod iter; -mod lane_count; mod masks; mod ops; mod select; @@ -27,8 +26,8 @@ pub mod simd { pub use crate::core_simd::alias::*; pub use crate::core_simd::cast::*; - pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount}; pub use crate::core_simd::masks::*; + pub use crate::core_simd::select::*; pub use crate::core_simd::swizzle::*; pub use crate::core_simd::to_bytes::ToBytes; pub use crate::core_simd::vector::*; diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs index f36e8d01a73bb..eb6601f734831 100644 --- a/crates/core_simd/src/ops.rs +++ b/crates/core_simd/src/ops.rs @@ -1,4 +1,4 @@ -use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount, cmp::SimdPartialEq}; +use crate::simd::{Select, Simd, SimdElement, cmp::SimdPartialEq}; use core::ops::{Add, Mul}; use core::ops::{BitAnd, BitOr, BitXor}; use core::ops::{Div, Rem, Sub}; @@ -12,7 +12,6 @@ mod unary; impl core::ops::Index for Simd where T: SimdElement, - LaneCount: SupportedLaneCount, I: core::slice::SliceIndex<[T]>, { type Output = I::Output; @@ -25,7 +24,6 @@ where impl core::ops::IndexMut for Simd where T: SimdElement, - LaneCount: SupportedLaneCount, I: core::slice::SliceIndex<[T]>, { #[inline] @@ -130,7 +128,6 @@ macro_rules! for_base_types { impl $op for Simd<$scalar, N> where $scalar: SimdElement, - LaneCount: SupportedLaneCount, { type Output = $out; diff --git a/crates/core_simd/src/ops/assign.rs b/crates/core_simd/src/ops/assign.rs index d21d867de26d6..c1830c35df778 100644 --- a/crates/core_simd/src/ops/assign.rs +++ b/crates/core_simd/src/ops/assign.rs @@ -21,7 +21,6 @@ macro_rules! assign_ops { where Self: $trait, T: SimdElement, - LaneCount: SupportedLaneCount, { #[inline] fn $assign_call(&mut self, rhs: U) { diff --git a/crates/core_simd/src/ops/deref.rs b/crates/core_simd/src/ops/deref.rs index 913cbbe977c46..360b83c403468 100644 --- a/crates/core_simd/src/ops/deref.rs +++ b/crates/core_simd/src/ops/deref.rs @@ -13,7 +13,6 @@ macro_rules! deref_lhs { where T: SimdElement, $simd: $trait<$simd, Output = $simd>, - LaneCount: SupportedLaneCount, { type Output = Simd; @@ -33,7 +32,6 @@ macro_rules! deref_rhs { where T: SimdElement, $simd: $trait<$simd, Output = $simd>, - LaneCount: SupportedLaneCount, { type Output = Simd; @@ -64,7 +62,6 @@ macro_rules! deref_ops { where T: SimdElement, $simd: $trait<$simd, Output = $simd>, - LaneCount: SupportedLaneCount, { type Output = $simd; diff --git a/crates/core_simd/src/ops/shift_scalar.rs b/crates/core_simd/src/ops/shift_scalar.rs index f5115a5a5e935..7ca83dc40f617 100644 --- a/crates/core_simd/src/ops/shift_scalar.rs +++ b/crates/core_simd/src/ops/shift_scalar.rs @@ -1,13 +1,11 @@ // Shift operations uniquely typically only have a scalar on the right-hand side. // Here, we implement shifts for scalar RHS arguments. -use crate::simd::{LaneCount, Simd, SupportedLaneCount}; +use crate::simd::Simd; macro_rules! impl_splatted_shifts { { impl $trait:ident :: $trait_fn:ident for $ty:ty } => { impl core::ops::$trait<$ty> for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] @@ -17,8 +15,6 @@ macro_rules! impl_splatted_shifts { } impl core::ops::$trait<&$ty> for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, { type Output = Self; #[inline] @@ -28,8 +24,6 @@ macro_rules! impl_splatted_shifts { } impl<'lhs, const N: usize> core::ops::$trait<$ty> for &'lhs Simd<$ty, N> - where - LaneCount: SupportedLaneCount, { type Output = Simd<$ty, N>; #[inline] @@ -39,8 +33,6 @@ macro_rules! impl_splatted_shifts { } impl<'lhs, const N: usize> core::ops::$trait<&$ty> for &'lhs Simd<$ty, N> - where - LaneCount: SupportedLaneCount, { type Output = Simd<$ty, N>; #[inline] diff --git a/crates/core_simd/src/ops/unary.rs b/crates/core_simd/src/ops/unary.rs index 412a5b801171b..e1c06167f9790 100644 --- a/crates/core_simd/src/ops/unary.rs +++ b/crates/core_simd/src/ops/unary.rs @@ -1,4 +1,4 @@ -use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; +use crate::simd::{Simd, SimdElement}; use core::ops::{Neg, Not}; // unary ops macro_rules! neg { @@ -6,7 +6,6 @@ macro_rules! neg { $(impl Neg for Simd<$scalar, N> where $scalar: SimdElement, - LaneCount: SupportedLaneCount, { type Output = Self; @@ -40,7 +39,6 @@ macro_rules! not { $(impl Not for Simd<$scalar, N> where $scalar: SimdElement, - LaneCount: SupportedLaneCount, { type Output = Self; diff --git a/crates/core_simd/src/select.rs b/crates/core_simd/src/select.rs index f33aa261a928f..404f54d8f3827 100644 --- a/crates/core_simd/src/select.rs +++ b/crates/core_simd/src/select.rs @@ -1,54 +1,155 @@ -use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount}; +use crate::simd::{FixEndianness, Mask, MaskElement, Simd, SimdElement}; -impl Mask +/// Choose elements from two vectors using a mask. +/// +/// For each element in the mask, choose the corresponding element from `true_values` if +/// that element mask is true, and `false_values` if that element mask is false. +/// +/// If the mask is `u64`, it's treated as a bitmask with the least significant bit +/// corresponding to the first element. +/// +/// # Examples +/// +/// ## Selecting values from `Simd` +/// ``` +/// # #![feature(portable_simd)] +/// # #[cfg(feature = "as_crate")] use core_simd::simd; +/// # #[cfg(not(feature = "as_crate"))] use core::simd; +/// # use simd::{Simd, Mask, Select}; +/// let a = Simd::from_array([0, 1, 2, 3]); +/// let b = Simd::from_array([4, 5, 6, 7]); +/// let mask = Mask::::from_array([true, false, false, true]); +/// let c = mask.select(a, b); +/// assert_eq!(c.to_array(), [0, 5, 6, 3]); +/// ``` +/// +/// ## Selecting values from `Mask` +/// ``` +/// # #![feature(portable_simd)] +/// # #[cfg(feature = "as_crate")] use core_simd::simd; +/// # #[cfg(not(feature = "as_crate"))] use core::simd; +/// # use simd::{Mask, Select}; +/// let a = Mask::::from_array([true, true, false, false]); +/// let b = Mask::::from_array([false, false, true, true]); +/// let mask = Mask::::from_array([true, false, false, true]); +/// let c = mask.select(a, b); +/// assert_eq!(c.to_array(), [true, false, true, false]); +/// ``` +/// +/// ## Selecting with a bitmask +/// ``` +/// # #![feature(portable_simd)] +/// # #[cfg(feature = "as_crate")] use core_simd::simd; +/// # #[cfg(not(feature = "as_crate"))] use core::simd; +/// # use simd::{Mask, Select}; +/// let a = Mask::::from_array([true, true, false, false]); +/// let b = Mask::::from_array([false, false, true, true]); +/// let mask = 0b1001; +/// let c = mask.select(a, b); +/// assert_eq!(c.to_array(), [true, false, true, false]); +/// ``` +pub trait Select { + /// Choose elements + fn select(self, true_values: T, false_values: T) -> T; +} + +impl Select> for Mask +where + T: SimdElement, + U: MaskElement, +{ + #[inline] + fn select(self, true_values: Simd, false_values: Simd) -> Simd { + // Safety: + // simd_as between masks is always safe (they're vectors of ints). + // simd_select uses a mask that matches the width and number of elements + unsafe { + let mask: Simd = core::intrinsics::simd::simd_as(self.to_simd()); + core::intrinsics::simd::simd_select(mask, true_values, false_values) + } + } +} + +impl Select> for u64 +where + T: SimdElement, +{ + #[inline] + fn select(self, true_values: Simd, false_values: Simd) -> Simd { + const { + assert!(N <= 64, "number of elements can't be greater than 64"); + } + + #[inline] + unsafe fn select_impl( + bitmask: U, + true_values: Simd, + false_values: Simd, + ) -> Simd + where + T: SimdElement, + { + let default = true_values[0]; + let true_values = true_values.resize::(default); + let false_values = false_values.resize::(default); + + // LLVM assumes bit order should match endianness + let bitmask = bitmask.fix_endianness(); + + // Safety: the caller guarantees that the size of U matches M + let selected = unsafe { + core::intrinsics::simd::simd_select_bitmask(bitmask, true_values, false_values) + }; + + selected.resize::(default) + } + + // TODO modify simd_bitmask_select to truncate input, making this unnecessary + if N <= 8 { + let bitmask = self as u8; + // Safety: bitmask matches length + unsafe { select_impl::(bitmask, true_values, false_values) } + } else if N <= 16 { + let bitmask = self as u16; + // Safety: bitmask matches length + unsafe { select_impl::(bitmask, true_values, false_values) } + } else if N <= 32 { + let bitmask = self as u32; + // Safety: bitmask matches length + unsafe { select_impl::(bitmask, true_values, false_values) } + } else { + let bitmask = self; + // Safety: bitmask matches length + unsafe { select_impl::(bitmask, true_values, false_values) } + } + } +} + +impl Select> for Mask where T: MaskElement, - LaneCount: SupportedLaneCount, + U: MaskElement, { - /// Choose elements from two vectors. - /// - /// For each element in the mask, choose the corresponding element from `true_values` if - /// that element mask is true, and `false_values` if that element mask is false. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::{Simd, Mask}; - /// let a = Simd::from_array([0, 1, 2, 3]); - /// let b = Simd::from_array([4, 5, 6, 7]); - /// let mask = Mask::from_array([true, false, false, true]); - /// let c = mask.select(a, b); - /// assert_eq!(c.to_array(), [0, 5, 6, 3]); - /// ``` #[inline] - #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn select(self, true_values: Simd, false_values: Simd) -> Simd - where - U: SimdElement, - { - // Safety: The mask has been cast to a vector of integers, - // and the operands to select between are vectors of the same type and length. - unsafe { core::intrinsics::simd::simd_select(self.to_int(), true_values, false_values) } + fn select(self, true_values: Mask, false_values: Mask) -> Mask { + let selected: Simd = + Select::select(self, true_values.to_simd(), false_values.to_simd()); + + // Safety: all values come from masks + unsafe { Mask::from_simd_unchecked(selected) } } +} - /// Choose elements from two masks. - /// - /// For each element in the mask, choose the corresponding element from `true_values` if - /// that element mask is true, and `false_values` if that element mask is false. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::Mask; - /// let a = Mask::::from_array([true, true, false, false]); - /// let b = Mask::::from_array([false, false, true, true]); - /// let mask = Mask::::from_array([true, false, false, true]); - /// let c = mask.select_mask(a, b); - /// assert_eq!(c.to_array(), [true, false, true, false]); - /// ``` +impl Select> for u64 +where + T: MaskElement, +{ #[inline] - #[must_use = "method returns a new mask and does not mutate the original inputs"] - pub fn select_mask(self, true_values: Self, false_values: Self) -> Self { - self & true_values | !self & false_values + fn select(self, true_values: Mask, false_values: Mask) -> Mask { + let selected: Simd = + Select::select(self, true_values.to_simd(), false_values.to_simd()); + + // Safety: all values come from masks + unsafe { Mask::from_simd_unchecked(selected) } } } diff --git a/crates/core_simd/src/simd/cmp/eq.rs b/crates/core_simd/src/simd/cmp/eq.rs index 2312ba401fa78..d553d6c040c91 100644 --- a/crates/core_simd/src/simd/cmp/eq.rs +++ b/crates/core_simd/src/simd/cmp/eq.rs @@ -1,5 +1,5 @@ use crate::simd::{ - LaneCount, Mask, Simd, SimdElement, SupportedLaneCount, + Mask, Simd, SimdElement, ptr::{SimdConstPtr, SimdMutPtr}, }; @@ -21,8 +21,6 @@ macro_rules! impl_number { { $($number:ty),* } => { $( impl SimdPartialEq for Simd<$number, N> - where - LaneCount: SupportedLaneCount, { type Mask = Mask<<$number as SimdElement>::Mask, N>; @@ -30,14 +28,14 @@ macro_rules! impl_number { fn simd_eq(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_eq(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_eq(self, other)) } } #[inline] fn simd_ne(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ne(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ne(self, other)) } } } )* @@ -50,8 +48,6 @@ macro_rules! impl_mask { { $($integer:ty),* } => { $( impl SimdPartialEq for Mask<$integer, N> - where - LaneCount: SupportedLaneCount, { type Mask = Self; @@ -59,14 +55,14 @@ macro_rules! impl_mask { fn simd_eq(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_eq(self.to_int(), other.to_int())) } + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_eq(self.to_simd(), other.to_simd())) } } #[inline] fn simd_ne(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_ne(self.to_int(), other.to_int())) } + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ne(self.to_simd(), other.to_simd())) } } } )* @@ -75,10 +71,7 @@ macro_rules! impl_mask { impl_mask! { i8, i16, i32, i64, isize } -impl SimdPartialEq for Simd<*const T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdPartialEq for Simd<*const T, N> { type Mask = Mask; #[inline] @@ -92,10 +85,7 @@ where } } -impl SimdPartialEq for Simd<*mut T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdPartialEq for Simd<*mut T, N> { type Mask = Mask; #[inline] diff --git a/crates/core_simd/src/simd/cmp/ord.rs b/crates/core_simd/src/simd/cmp/ord.rs index e813e7613032c..5672fbbf54caa 100644 --- a/crates/core_simd/src/simd/cmp/ord.rs +++ b/crates/core_simd/src/simd/cmp/ord.rs @@ -1,5 +1,5 @@ use crate::simd::{ - LaneCount, Mask, Simd, SupportedLaneCount, + Mask, Select, Simd, cmp::SimdPartialEq, ptr::{SimdConstPtr, SimdMutPtr}, }; @@ -49,41 +49,37 @@ macro_rules! impl_integer { { $($integer:ty),* } => { $( impl SimdPartialOrd for Simd<$integer, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_lt(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_lt(self, other)) } } #[inline] fn simd_le(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_le(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_le(self, other)) } } #[inline] fn simd_gt(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_gt(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_gt(self, other)) } } #[inline] fn simd_ge(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ge(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ge(self, other)) } } } impl SimdOrd for Simd<$integer, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn simd_max(self, other: Self) -> Self { @@ -115,35 +111,33 @@ macro_rules! impl_float { { $($float:ty),* } => { $( impl SimdPartialOrd for Simd<$float, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_lt(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_lt(self, other)) } } #[inline] fn simd_le(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_le(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_le(self, other)) } } #[inline] fn simd_gt(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_gt(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_gt(self, other)) } } #[inline] fn simd_ge(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ge(self, other)) } + unsafe { Mask::from_simd_unchecked(core::intrinsics::simd::simd_ge(self, other)) } } } )* @@ -156,50 +150,46 @@ macro_rules! impl_mask { { $($integer:ty),* } => { $( impl SimdPartialOrd for Mask<$integer, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_lt(self.to_int(), other.to_int())) } + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_lt(self.to_simd(), other.to_simd())) } } #[inline] fn simd_le(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_le(self.to_int(), other.to_int())) } + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_le(self.to_simd(), other.to_simd())) } } #[inline] fn simd_gt(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_gt(self.to_int(), other.to_int())) } + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_gt(self.to_simd(), other.to_simd())) } } #[inline] fn simd_ge(self, other: Self) -> Self::Mask { // Safety: `self` is a vector, and the result of the comparison // is always a valid mask. - unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_ge(self.to_int(), other.to_int())) } + unsafe { Self::from_simd_unchecked(core::intrinsics::simd::simd_ge(self.to_simd(), other.to_simd())) } } } impl SimdOrd for Mask<$integer, N> - where - LaneCount: SupportedLaneCount, { #[inline] fn simd_max(self, other: Self) -> Self { - self.simd_gt(other).select_mask(other, self) + self.simd_gt(other).select(other, self) } #[inline] fn simd_min(self, other: Self) -> Self { - self.simd_lt(other).select_mask(other, self) + self.simd_lt(other).select(other, self) } #[inline] @@ -218,10 +208,7 @@ macro_rules! impl_mask { impl_mask! { i8, i16, i32, i64, isize } -impl SimdPartialOrd for Simd<*const T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdPartialOrd for Simd<*const T, N> { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { self.addr().simd_lt(other.addr()) @@ -243,10 +230,7 @@ where } } -impl SimdOrd for Simd<*const T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdOrd for Simd<*const T, N> { #[inline] fn simd_max(self, other: Self) -> Self { self.simd_lt(other).select(other, self) @@ -268,10 +252,7 @@ where } } -impl SimdPartialOrd for Simd<*mut T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdPartialOrd for Simd<*mut T, N> { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { self.addr().simd_lt(other.addr()) @@ -293,10 +274,7 @@ where } } -impl SimdOrd for Simd<*mut T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdOrd for Simd<*mut T, N> { #[inline] fn simd_max(self, other: Self) -> Self { self.simd_lt(other).select(other, self) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index b5972c47373bb..efd7c2469512b 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -1,6 +1,6 @@ use super::sealed::Sealed; use crate::simd::{ - LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount, + Mask, Select, Simd, SimdCast, SimdElement, cmp::{SimdPartialEq, SimdPartialOrd}, }; @@ -240,15 +240,9 @@ pub trait SimdFloat: Copy + Sealed { macro_rules! impl_trait { { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => { $( - impl Sealed for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, - { - } + impl Sealed for Simd<$ty, N> {} impl SimdFloat for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, { type Mask = Mask<<$mask_ty as SimdElement>::Mask, N>; type Scalar = $ty; diff --git a/crates/core_simd/src/simd/num/int.rs b/crates/core_simd/src/simd/num/int.rs index e7253313f036c..eee54d3968808 100644 --- a/crates/core_simd/src/simd/num/int.rs +++ b/crates/core_simd/src/simd/num/int.rs @@ -1,7 +1,6 @@ use super::sealed::Sealed; use crate::simd::{ - LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd, - cmp::SimdPartialOrd, num::SimdUint, + Mask, Select, Simd, SimdCast, SimdElement, cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint, }; /// Operations on SIMD vectors of signed integers. @@ -242,16 +241,9 @@ pub trait SimdInt: Copy + Sealed { macro_rules! impl_trait { { $($ty:ident ($unsigned:ident)),* } => { $( - impl Sealed for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, - { - } + impl Sealed for Simd<$ty, N> {} - impl SimdInt for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, - { + impl SimdInt for Simd<$ty, N> { type Mask = Mask<<$ty as SimdElement>::Mask, N>; type Scalar = $ty; type Unsigned = Simd<$unsigned, N>; diff --git a/crates/core_simd/src/simd/num/uint.rs b/crates/core_simd/src/simd/num/uint.rs index e3ba8658bd803..606107a1f06f8 100644 --- a/crates/core_simd/src/simd/num/uint.rs +++ b/crates/core_simd/src/simd/num/uint.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd}; +use crate::simd::{Simd, SimdCast, SimdElement, cmp::SimdOrd}; /// Operations on SIMD vectors of unsigned integers. pub trait SimdUint: Copy + Sealed { @@ -124,15 +124,9 @@ pub trait SimdUint: Copy + Sealed { macro_rules! impl_trait { { $($ty:ident ($signed:ident)),* } => { $( - impl Sealed for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, - { - } + impl Sealed for Simd<$ty, N> {} impl SimdUint for Simd<$ty, N> - where - LaneCount: SupportedLaneCount, { type Scalar = $ty; type Cast = Simd; diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index 36452e7ae920d..7ef9dc21373ec 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount, cmp::SimdPartialEq, num::SimdUint}; +use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: Copy + Sealed { @@ -88,12 +88,9 @@ pub trait SimdConstPtr: Copy + Sealed { fn wrapping_sub(self, count: Self::Usize) -> Self; } -impl Sealed for Simd<*const T, N> where LaneCount: SupportedLaneCount {} +impl Sealed for Simd<*const T, N> {} -impl SimdConstPtr for Simd<*const T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdConstPtr for Simd<*const T, N> { type Usize = Simd; type Isize = Simd; type CastPtr = Simd<*const U, N>; diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index c644f390c20a5..3b9b75ddf5660 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount, cmp::SimdPartialEq, num::SimdUint}; +use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: Copy + Sealed { @@ -85,12 +85,9 @@ pub trait SimdMutPtr: Copy + Sealed { fn wrapping_sub(self, count: Self::Usize) -> Self; } -impl Sealed for Simd<*mut T, N> where LaneCount: SupportedLaneCount {} +impl Sealed for Simd<*mut T, N> {} -impl SimdMutPtr for Simd<*mut T, N> -where - LaneCount: SupportedLaneCount, -{ +impl SimdMutPtr for Simd<*mut T, N> { type Usize = Simd; type Isize = Simd; type CastPtr = Simd<*mut U, N>; diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index dbdd6ef40eba7..02dcd71356dd6 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -1,4 +1,4 @@ -use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount}; +use crate::simd::{Mask, MaskElement, Simd, SimdElement}; /// Constructs a new SIMD vector by copying elements from selected elements in other vectors. /// @@ -82,8 +82,6 @@ pub trait Swizzle { fn swizzle(vector: Simd) -> Simd where T: SimdElement, - LaneCount: SupportedLaneCount, - LaneCount: SupportedLaneCount, { // Safety: `vector` is a vector, and the index is a const vector of u32. unsafe { @@ -122,8 +120,6 @@ pub trait Swizzle { fn concat_swizzle(first: Simd, second: Simd) -> Simd where T: SimdElement, - LaneCount: SupportedLaneCount, - LaneCount: SupportedLaneCount, { // Safety: `first` and `second` are vectors, and the index is a const vector of u32. unsafe { @@ -161,11 +157,9 @@ pub trait Swizzle { fn swizzle_mask(mask: Mask) -> Mask where T: MaskElement, - LaneCount: SupportedLaneCount, - LaneCount: SupportedLaneCount, { // SAFETY: all elements of this mask come from another mask - unsafe { Mask::from_int_unchecked(Self::swizzle(mask.to_int())) } + unsafe { Mask::from_simd_unchecked(Self::swizzle(mask.to_simd())) } } /// Creates a new mask from the elements of `first` and `second`. @@ -177,18 +171,17 @@ pub trait Swizzle { fn concat_swizzle_mask(first: Mask, second: Mask) -> Mask where T: MaskElement, - LaneCount: SupportedLaneCount, - LaneCount: SupportedLaneCount, { // SAFETY: all elements of this mask come from another mask - unsafe { Mask::from_int_unchecked(Self::concat_swizzle(first.to_int(), second.to_int())) } + unsafe { + Mask::from_simd_unchecked(Self::concat_swizzle(first.to_simd(), second.to_simd())) + } } } impl Simd where T: SimdElement, - LaneCount: SupportedLaneCount, { /// Reverse the order of the elements in the vector. #[inline] @@ -462,10 +455,7 @@ where /// ``` #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn resize(self, value: T) -> Simd - where - LaneCount: SupportedLaneCount, - { + pub fn resize(self, value: T) -> Simd { struct Resize; impl Swizzle for Resize { const INDEX: [usize; M] = const { @@ -493,10 +483,7 @@ where /// ``` #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn extract(self) -> Simd - where - LaneCount: SupportedLaneCount, - { + pub fn extract(self) -> Simd { struct Extract; impl Swizzle for Extract { const INDEX: [usize; LEN] = const { @@ -517,14 +504,13 @@ where impl Mask where T: MaskElement, - LaneCount: SupportedLaneCount, { /// Reverse the order of the elements in the mask. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn reverse(self) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().reverse()) } + unsafe { Self::from_simd_unchecked(self.to_simd().reverse()) } } /// Rotates the mask such that the first `OFFSET` elements of the slice move to the end @@ -534,7 +520,7 @@ where #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn rotate_elements_left(self) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_left::()) } + unsafe { Self::from_simd_unchecked(self.to_simd().rotate_elements_left::()) } } /// Rotates the mask such that the first `self.len() - OFFSET` elements of the mask move to @@ -544,7 +530,7 @@ where #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn rotate_elements_right(self) -> Self { // Safety: swizzles are safe for masks - unsafe { Self::from_int_unchecked(self.to_int().rotate_elements_right::()) } + unsafe { Self::from_simd_unchecked(self.to_simd().rotate_elements_right::()) } } /// Shifts the mask elements to the left by `OFFSET`, filling in with @@ -554,7 +540,7 @@ where pub fn shift_elements_left(self, padding: bool) -> Self { // Safety: swizzles are safe for masks unsafe { - Self::from_int_unchecked(self.to_int().shift_elements_left::(if padding { + Self::from_simd_unchecked(self.to_simd().shift_elements_left::(if padding { T::TRUE } else { T::FALSE @@ -569,7 +555,7 @@ where pub fn shift_elements_right(self, padding: bool) -> Self { // Safety: swizzles are safe for masks unsafe { - Self::from_int_unchecked(self.to_int().shift_elements_right::(if padding { + Self::from_simd_unchecked(self.to_simd().shift_elements_right::(if padding { T::TRUE } else { T::FALSE @@ -598,9 +584,9 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn interleave(self, other: Self) -> (Self, Self) { - let (lo, hi) = self.to_int().interleave(other.to_int()); + let (lo, hi) = self.to_simd().interleave(other.to_simd()); // Safety: swizzles are safe for masks - unsafe { (Self::from_int_unchecked(lo), Self::from_int_unchecked(hi)) } + unsafe { (Self::from_simd_unchecked(lo), Self::from_simd_unchecked(hi)) } } /// Deinterleave two masks. @@ -627,12 +613,12 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn deinterleave(self, other: Self) -> (Self, Self) { - let (even, odd) = self.to_int().deinterleave(other.to_int()); + let (even, odd) = self.to_simd().deinterleave(other.to_simd()); // Safety: swizzles are safe for masks unsafe { ( - Self::from_int_unchecked(even), - Self::from_int_unchecked(odd), + Self::from_simd_unchecked(even), + Self::from_simd_unchecked(odd), ) } } @@ -653,13 +639,10 @@ where /// ``` #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn resize(self, value: bool) -> Mask - where - LaneCount: SupportedLaneCount, - { + pub fn resize(self, value: bool) -> Mask { // Safety: swizzles are safe for masks unsafe { - Mask::::from_int_unchecked(self.to_int().resize::(if value { + Mask::::from_simd_unchecked(self.to_simd().resize::(if value { T::TRUE } else { T::FALSE @@ -679,11 +662,8 @@ where /// ``` #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn extract(self) -> Mask - where - LaneCount: SupportedLaneCount, - { + pub fn extract(self) -> Mask { // Safety: swizzles are safe for masks - unsafe { Mask::::from_int_unchecked(self.to_int().extract::()) } + unsafe { Mask::::from_simd_unchecked(self.to_simd().extract::()) } } } diff --git a/crates/core_simd/src/swizzle_dyn.rs b/crates/core_simd/src/swizzle_dyn.rs index 773bd028bae09..ae0b174973da7 100644 --- a/crates/core_simd/src/swizzle_dyn.rs +++ b/crates/core_simd/src/swizzle_dyn.rs @@ -1,10 +1,7 @@ -use crate::simd::{LaneCount, Simd, SupportedLaneCount}; +use crate::simd::Simd; use core::mem; -impl Simd -where - LaneCount: SupportedLaneCount, -{ +impl Simd { /// Swizzle a vector of bytes according to the index vector. /// Indices within range select the appropriate byte. /// Indices "out of bounds" instead select 0. @@ -139,7 +136,7 @@ unsafe fn armv7_neon_swizzle_u8x16(bytes: Simd, idxs: Simd) -> S #[inline] #[allow(clippy::let_and_return)] unsafe fn avx2_pshufb(bytes: Simd, idxs: Simd) -> Simd { - use crate::simd::cmp::SimdPartialOrd; + use crate::simd::{Select, cmp::SimdPartialOrd}; #[cfg(target_arch = "x86")] use core::arch::x86; #[cfg(target_arch = "x86_64")] @@ -184,10 +181,7 @@ unsafe fn transize( f: unsafe fn(T, T) -> T, a: Simd, b: Simd, -) -> Simd -where - LaneCount: SupportedLaneCount, -{ +) -> Simd { // SAFETY: Same obligation to use this function as to use mem::transmute_copy. unsafe { mem::transmute_copy(&f(mem::transmute_copy(&a), mem::transmute_copy(&b))) } } @@ -196,11 +190,8 @@ where #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[allow(unused)] #[inline(always)] -fn zeroing_idxs(idxs: Simd) -> Simd -where - LaneCount: SupportedLaneCount, -{ - use crate::simd::cmp::SimdPartialOrd; +fn zeroing_idxs(idxs: Simd) -> Simd { + use crate::simd::{Select, cmp::SimdPartialOrd}; idxs.simd_lt(Simd::splat(N as u8)) .select(idxs, Simd::splat(u8::MAX)) } diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index fee2cc06c5b09..1fd285e457db8 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -1,12 +1,12 @@ use crate::simd::{ - LaneCount, Simd, SimdElement, SupportedLaneCount, + Simd, SimdElement, num::{SimdFloat, SimdInt, SimdUint}, }; mod sealed { use super::*; pub trait Sealed {} - impl Sealed for Simd where LaneCount: SupportedLaneCount {} + impl Sealed for Simd {} } use sealed::Sealed; diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index f40031f8c4da7..5b3a689f3611b 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -1,5 +1,7 @@ +use core::intrinsics::simd::SimdAlign; + use crate::simd::{ - LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle, + Mask, MaskElement, cmp::SimdPartialOrd, num::SimdUint, ptr::{SimdConstPtr, SimdMutPtr}, @@ -51,6 +53,8 @@ use crate::simd::{ /// Thus it is sound to [`transmute`] `Simd` to `[T; N]` and should optimize to "zero cost", /// but the reverse transmutation may require a copy the compiler cannot simply elide. /// +/// `N` cannot be 0 and may be at most 64. This limit may be increased in the future. +/// /// # ABI "Features" /// Due to Rust's safety guarantees, `Simd` is currently passed and returned via memory, /// not SIMD registers, except as an optimization. Using `#[inline]` on functions that accept @@ -100,14 +104,13 @@ use crate::simd::{ // avoided, as it will likely become illegal on `#[repr(simd)]` structs in the future. It also // causes rustc to emit illegal LLVM IR in some cases. #[repr(simd, packed)] +#[rustc_simd_monomorphize_lane_limit = "64"] pub struct Simd([T; N]) where - LaneCount: SupportedLaneCount, T: SimdElement; impl Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { /// Number of elements in this vector. @@ -146,30 +149,8 @@ where #[inline] #[rustc_const_unstable(feature = "portable_simd", issue = "86656")] pub const fn splat(value: T) -> Self { - const fn splat_const(value: T) -> Simd - where - T: SimdElement, - LaneCount: SupportedLaneCount, - { - Simd::from_array([value; N]) - } - - fn splat_rt(value: T) -> Simd - where - T: SimdElement, - LaneCount: SupportedLaneCount, - { - // This is preferred over `[value; N]`, since it's explicitly a splat: - // https://github.com/rust-lang/rust/issues/97804 - struct Splat; - impl Swizzle for Splat { - const INDEX: [usize; N] = [0; N]; - } - - Splat::swizzle::(Simd::::from([value])) - } - - core::intrinsics::const_eval_select((value,), splat_const, splat_rt) + // SAFETY: T is a SimdElement, and the item type of Self. + unsafe { core::intrinsics::simd::simd_splat(value) } } /// Returns an array reference containing the entire SIMD vector. @@ -195,7 +176,7 @@ where /// Returns a mutable array reference containing the entire SIMD vector. #[inline] - pub fn as_mut_array(&mut self) -> &mut [T; N] { + pub const fn as_mut_array(&mut self) -> &mut [T; N] { // SAFETY: `Simd` is just an overaligned `[T; N]` with // potential padding at the end, so pointer casting to a // `&mut [T; N]` is safe. @@ -324,7 +305,7 @@ where /// ``` #[inline] #[track_caller] - pub fn copy_to_slice(self, slice: &mut [T]) { + pub const fn copy_to_slice(self, slice: &mut [T]) { assert!( slice.len() >= Self::LEN, "slice length must be at least the number of elements" @@ -465,7 +446,7 @@ where /// value from `or` is passed through. /// /// # Safety - /// Enabled `ptr` elements must be safe to read as if by `std::ptr::read`. + /// Enabled `ptr` elements must be safe to read as if by `core::ptr::read`. #[must_use] #[inline] pub unsafe fn load_select_ptr( @@ -475,12 +456,11 @@ where ) -> Self { // SAFETY: The safety of reading elements through `ptr` is ensured by the caller. unsafe { - core::intrinsics::simd::simd_masked_load::< - _, - _, - _, - { core::intrinsics::simd::SimdAlign::Element }, - >(enable.to_int(), ptr, or) + core::intrinsics::simd::simd_masked_load::<_, _, _, { SimdAlign::Element }>( + enable.to_simd(), + ptr, + or, + ) } } @@ -659,7 +639,7 @@ where or: Self, ) -> Self { // Safety: The caller is responsible for upholding all invariants - unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_int()) } + unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_simd()) } } /// Conditionally write contiguous elements to `slice`. The `enable` mask controls @@ -731,12 +711,11 @@ where pub unsafe fn store_select_ptr(self, ptr: *mut T, enable: Mask<::Mask, N>) { // SAFETY: The safety of writing elements through `ptr` is ensured by the caller. unsafe { - core::intrinsics::simd::simd_masked_store::< - _, - _, - _, - { core::intrinsics::simd::SimdAlign::Element }, - >(enable.to_int(), ptr, self) + core::intrinsics::simd::simd_masked_store::<_, _, _, { SimdAlign::Element }>( + enable.to_simd(), + ptr, + self, + ) } } @@ -896,20 +875,14 @@ where #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn scatter_select_ptr(self, dest: Simd<*mut T, N>, enable: Mask) { // Safety: The caller is responsible for upholding all invariants - unsafe { core::intrinsics::simd::simd_scatter(self, dest, enable.to_int()) } + unsafe { core::intrinsics::simd::simd_scatter(self, dest, enable.to_simd()) } } } -impl Copy for Simd -where - LaneCount: SupportedLaneCount, - T: SimdElement, -{ -} +impl Copy for Simd where T: SimdElement {} impl Clone for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -920,7 +893,6 @@ where impl Default for Simd where - LaneCount: SupportedLaneCount, T: SimdElement + Default, { #[inline] @@ -931,7 +903,6 @@ where impl PartialEq for Simd where - LaneCount: SupportedLaneCount, T: SimdElement + PartialEq, { #[inline] @@ -940,7 +911,7 @@ where let mask = unsafe { let tfvec: Simd<::Mask, N> = core::intrinsics::simd::simd_eq(*self, *other); - Mask::from_int_unchecked(tfvec) + Mask::from_simd_unchecked(tfvec) }; // Two vectors are equal if all elements are equal when compared elementwise @@ -954,7 +925,7 @@ where let mask = unsafe { let tfvec: Simd<::Mask, N> = core::intrinsics::simd::simd_ne(*self, *other); - Mask::from_int_unchecked(tfvec) + Mask::from_simd_unchecked(tfvec) }; // Two vectors are non-equal if any elements are non-equal when compared elementwise @@ -965,7 +936,6 @@ where /// Lexicographic order. For the SIMD elementwise minimum and maximum, use simd_min and simd_max instead. impl PartialOrd for Simd where - LaneCount: SupportedLaneCount, T: SimdElement + PartialOrd, { #[inline] @@ -975,17 +945,11 @@ where } } -impl Eq for Simd -where - LaneCount: SupportedLaneCount, - T: SimdElement + Eq, -{ -} +impl Eq for Simd where T: SimdElement + Eq {} /// Lexicographic order. For the SIMD elementwise minimum and maximum, use simd_min and simd_max instead. impl Ord for Simd where - LaneCount: SupportedLaneCount, T: SimdElement + Ord, { #[inline] @@ -997,7 +961,6 @@ where impl core::hash::Hash for Simd where - LaneCount: SupportedLaneCount, T: SimdElement + core::hash::Hash, { #[inline] @@ -1012,7 +975,6 @@ where // array references impl AsRef<[T; N]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -1023,7 +985,6 @@ where impl AsMut<[T; N]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -1035,7 +996,6 @@ where // slice references impl AsRef<[T]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -1046,7 +1006,6 @@ where impl AsMut<[T]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -1058,7 +1017,6 @@ where // vector/array conversion impl From<[T; N]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -1069,7 +1027,6 @@ where impl From> for [T; N] where - LaneCount: SupportedLaneCount, T: SimdElement, { #[inline] @@ -1080,7 +1037,6 @@ where impl TryFrom<&[T]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { type Error = core::array::TryFromSliceError; @@ -1093,7 +1049,6 @@ where impl TryFrom<&mut [T]> for Simd where - LaneCount: SupportedLaneCount, T: SimdElement, { type Error = core::array::TryFromSliceError; @@ -1231,10 +1186,7 @@ where } #[inline] -fn lane_indices() -> Simd -where - LaneCount: SupportedLaneCount, -{ +fn lane_indices() -> Simd { #![allow(clippy::needless_range_loop)] let mut index = [0; N]; for i in 0..N { @@ -1246,7 +1198,6 @@ where #[inline] fn mask_up_to(len: usize) -> Mask where - LaneCount: SupportedLaneCount, M: MaskElement, { let index = lane_indices::(); diff --git a/crates/core_simd/src/vendor/loongarch64.rs b/crates/core_simd/src/vendor/loongarch64.rs index 1290bc166b2b8..1f84cdb971ecb 100644 --- a/crates/core_simd/src/vendor/loongarch64.rs +++ b/crates/core_simd/src/vendor/loongarch64.rs @@ -1,31 +1,26 @@ use crate::simd::*; use core::arch::loongarch64::*; -from_transmute! { unsafe u8x16 => v16u8 } -from_transmute! { unsafe u8x32 => v32u8 } -from_transmute! { unsafe i8x16 => v16i8 } -from_transmute! { unsafe i8x32 => v32i8 } +from_transmute! { unsafe u8x16 => m128i } +from_transmute! { unsafe u8x32 => m256i } +from_transmute! { unsafe i8x16 => m128i } +from_transmute! { unsafe i8x32 => m256i } -from_transmute! { unsafe u16x8 => v8u16 } -from_transmute! { unsafe u16x16 => v16u16 } -from_transmute! { unsafe i16x8 => v8i16 } -from_transmute! { unsafe i16x16 => v16i16 } +from_transmute! { unsafe u16x8 => m128i } +from_transmute! { unsafe u16x16 => m256i } +from_transmute! { unsafe i16x8 => m128i } +from_transmute! { unsafe i16x16 => m256i } -from_transmute! { unsafe u32x4 => v4u32 } -from_transmute! { unsafe u32x8 => v8u32 } -from_transmute! { unsafe i32x4 => v4i32 } -from_transmute! { unsafe i32x8 => v8i32 } -from_transmute! { unsafe f32x4 => v4f32 } -from_transmute! { unsafe f32x8 => v8f32 } +from_transmute! { unsafe u32x4 => m128i } +from_transmute! { unsafe u32x8 => m256i } +from_transmute! { unsafe i32x4 => m128i } +from_transmute! { unsafe i32x8 => m256i } +from_transmute! { unsafe f32x4 => m128 } +from_transmute! { unsafe f32x8 => m256 } -from_transmute! { unsafe u64x2 => v2u64 } -from_transmute! { unsafe u64x4 => v4u64 } -from_transmute! { unsafe i64x2 => v2i64 } -from_transmute! { unsafe i64x4 => v4i64 } -from_transmute! { unsafe f64x2 => v2f64 } -from_transmute! { unsafe f64x4 => v4f64 } - -from_transmute! { unsafe usizex2 => v2u64 } -from_transmute! { unsafe usizex4 => v4u64 } -from_transmute! { unsafe isizex2 => v2i64 } -from_transmute! { unsafe isizex4 => v4i64 } +from_transmute! { unsafe u64x2 => m128i } +from_transmute! { unsafe u64x4 => m256i } +from_transmute! { unsafe i64x2 => m128i } +from_transmute! { unsafe i64x4 => m256i } +from_transmute! { unsafe f64x2 => m128d } +from_transmute! { unsafe f64x4 => m256d } diff --git a/crates/core_simd/src/vendor/wasm32.rs b/crates/core_simd/src/vendor/wasm32.rs index ef3baf885b0fb..1fdb2bc86d346 100644 --- a/crates/core_simd/src/vendor/wasm32.rs +++ b/crates/core_simd/src/vendor/wasm32.rs @@ -14,17 +14,3 @@ from_transmute! { unsafe f32x4 => v128 } from_transmute! { unsafe u64x2 => v128 } from_transmute! { unsafe i64x2 => v128 } from_transmute! { unsafe f64x2 => v128 } - -#[cfg(target_pointer_width = "32")] -mod p32 { - use super::*; - from_transmute! { unsafe usizex4 => v128 } - from_transmute! { unsafe isizex4 => v128 } -} - -#[cfg(target_pointer_width = "64")] -mod p64 { - use super::*; - from_transmute! { unsafe usizex2 => v128 } - from_transmute! { unsafe isizex2 => v128 } -} diff --git a/crates/core_simd/src/vendor/x86.rs b/crates/core_simd/src/vendor/x86.rs index 66aaf90eef597..eae42e6fd0d0a 100644 --- a/crates/core_simd/src/vendor/x86.rs +++ b/crates/core_simd/src/vendor/x86.rs @@ -39,25 +39,3 @@ from_transmute! { unsafe i64x8 => __m512i } from_transmute! { unsafe f64x2 => __m128d } from_transmute! { unsafe f64x4 => __m256d } from_transmute! { unsafe f64x8 => __m512d } - -#[cfg(target_pointer_width = "32")] -mod p32 { - use super::*; - from_transmute! { unsafe usizex4 => __m128i } - from_transmute! { unsafe usizex8 => __m256i } - from_transmute! { unsafe Simd => __m512i } - from_transmute! { unsafe isizex4 => __m128i } - from_transmute! { unsafe isizex8 => __m256i } - from_transmute! { unsafe Simd => __m512i } -} - -#[cfg(target_pointer_width = "64")] -mod p64 { - use super::*; - from_transmute! { unsafe usizex2 => __m128i } - from_transmute! { unsafe usizex4 => __m256i } - from_transmute! { unsafe usizex8 => __m512i } - from_transmute! { unsafe isizex2 => __m128i } - from_transmute! { unsafe isizex4 => __m256i } - from_transmute! { unsafe isizex8 => __m512i } -} diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs index 48786d02440b3..53fb2367b6055 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs @@ -65,9 +65,9 @@ macro_rules! test_mask_api { fn roundtrip_int_conversion() { let values = [true, false, false, true, false, false, true, false]; let mask = Mask::<$type, 8>::from_array(values); - let int = mask.to_int(); + let int = mask.to_simd(); assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]); - assert_eq!(Mask::<$type, 8>::from_int(int), mask); + assert_eq!(Mask::<$type, 8>::from_simd(int), mask); } #[test] diff --git a/crates/std_float/src/lib.rs b/crates/std_float/src/lib.rs index 148aa5f9f1771..b269efc9b1d76 100644 --- a/crates/std_float/src/lib.rs +++ b/crates/std_float/src/lib.rs @@ -11,7 +11,7 @@ use core_simd::simd; use core::intrinsics::simd as intrinsics; -use simd::{LaneCount, Simd, SupportedLaneCount}; +use simd::Simd; #[cfg(feature = "as_crate")] mod experimental { @@ -66,28 +66,43 @@ pub trait StdFloat: Sealed + Sized { /// Produces a vector where every element has the sine of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn sin(self) -> Self; + fn sin(self) -> Self { + unsafe { intrinsics::simd_fsin(self) } + } /// Produces a vector where every element has the cosine of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn cos(self) -> Self; + fn cos(self) -> Self { + unsafe { intrinsics::simd_fcos(self) } + } /// Produces a vector where every element has the exponential (base e) of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn exp(self) -> Self; + fn exp(self) -> Self { + unsafe { intrinsics::simd_fexp(self) } + } /// Produces a vector where every element has the exponential (base 2) of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn exp2(self) -> Self; + fn exp2(self) -> Self { + unsafe { intrinsics::simd_fexp2(self) } + } /// Produces a vector where every element has the natural logarithm of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn ln(self) -> Self; + fn ln(self) -> Self { + unsafe { intrinsics::simd_flog(self) } + } /// Produces a vector where every element has the logarithm with respect to an arbitrary /// in the equivalently-indexed elements in `self` and `base`. @@ -99,13 +114,19 @@ pub trait StdFloat: Sealed + Sized { /// Produces a vector where every element has the base-2 logarithm of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn log2(self) -> Self; + fn log2(self) -> Self { + unsafe { intrinsics::simd_flog2(self) } + } /// Produces a vector where every element has the base-10 logarithm of the value /// in the equivalently-indexed element in `self`. + #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - fn log10(self) -> Self; + fn log10(self) -> Self { + unsafe { intrinsics::simd_flog10(self) } + } /// Returns the smallest integer greater than or equal to each element. #[must_use = "method returns a new vector and does not mutate the original value"] @@ -140,68 +161,19 @@ pub trait StdFloat: Sealed + Sized { fn fract(self) -> Self; } -impl Sealed for Simd where LaneCount: SupportedLaneCount {} -impl Sealed for Simd where LaneCount: SupportedLaneCount {} - -macro_rules! impl_float { - { - $($fn:ident: $intrinsic:ident,)* - } => { - impl StdFloat for Simd - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn fract(self) -> Self { - self - self.trunc() - } - - $( - #[inline] - fn $fn(self) -> Self { - unsafe { intrinsics::$intrinsic(self) } - } - )* - } - - impl StdFloat for Simd - where - LaneCount: SupportedLaneCount, - { - #[inline] - fn fract(self) -> Self { - self - self.trunc() - } - - $( - #[inline] - fn $fn(self) -> Self { - // https://github.com/llvm/llvm-project/issues/83729 - #[cfg(target_arch = "aarch64")] - { - let mut ln = Self::splat(0f64); - for i in 0..N { - ln[i] = self[i].$fn() - } - ln - } - - #[cfg(not(target_arch = "aarch64"))] - { - unsafe { intrinsics::$intrinsic(self) } - } - } - )* - } +impl Sealed for Simd {} +impl Sealed for Simd {} + +impl StdFloat for Simd { + #[inline] + fn fract(self) -> Self { + self - self.trunc() } } -impl_float! { - sin: simd_fsin, - cos: simd_fcos, - exp: simd_fexp, - exp2: simd_fexp2, - ln: simd_flog, - log2: simd_flog2, - log10: simd_flog10, +impl StdFloat for Simd { + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } } diff --git a/crates/std_float/tests/float.rs b/crates/std_float/tests/float.rs index c66c968f8c667..c608ba49564e0 100644 --- a/crates/std_float/tests/float.rs +++ b/crates/std_float/tests/float.rs @@ -16,15 +16,33 @@ macro_rules! unary_test { } } -macro_rules! binary_test { +macro_rules! unary_approx_test { { $scalar:tt, $($func:tt),+ } => { test_helpers::test_lanes! { $( fn $func() { - test_helpers::test_binary_elementwise( + test_helpers::test_unary_elementwise_approx( + &core_simd::simd::Simd::<$scalar, LANES>::$func, + &$scalar::$func, + &|_| true, + 8, + ) + } + )* + } + } +} + +macro_rules! binary_approx_test { + { $scalar:tt, $($func:tt),+ } => { + test_helpers::test_lanes! { + $( + fn $func() { + test_helpers::test_binary_elementwise_approx( &core_simd::simd::Simd::<$scalar, LANES>::$func, &$scalar::$func, &|_, _| true, + 16, ) } )* @@ -53,10 +71,13 @@ macro_rules! impl_tests { mod $scalar { use std_float::StdFloat; - unary_test! { $scalar, sqrt, sin, cos, exp, exp2, ln, log2, log10, ceil, floor, round, trunc } - binary_test! { $scalar, log } + unary_test! { $scalar, sqrt, ceil, floor, round, trunc } ternary_test! { $scalar, mul_add } + // https://github.com/rust-lang/miri/issues/3555 + unary_approx_test! { $scalar, sin, cos, exp, exp2, ln, log2, log10 } + binary_approx_test! { $scalar, log } + test_helpers::test_lanes! { fn fract() { test_helpers::test_unary_elementwise_flush_subnormals( diff --git a/crates/test_helpers/Cargo.toml b/crates/test_helpers/Cargo.toml index a5359b9abc84d..408bb04c7aa40 100644 --- a/crates/test_helpers/Cargo.toml +++ b/crates/test_helpers/Cargo.toml @@ -6,3 +6,4 @@ publish = false [dependencies] proptest = { version = "0.10", default-features = false, features = ["alloc"] } +float-cmp = "0.10" diff --git a/crates/test_helpers/src/approxeq.rs b/crates/test_helpers/src/approxeq.rs new file mode 100644 index 0000000000000..57b43a16bc6fe --- /dev/null +++ b/crates/test_helpers/src/approxeq.rs @@ -0,0 +1,110 @@ +//! Compare numeric types approximately. + +use float_cmp::Ulps; + +pub trait ApproxEq { + fn approxeq(&self, other: &Self, _ulps: i64) -> bool; + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result; +} + +impl ApproxEq for bool { + fn approxeq(&self, other: &Self, _ulps: i64) -> bool { + self == other + } + + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +macro_rules! impl_integer_approxeq { + { $($type:ty),* } => { + $( + impl ApproxEq for $type { + fn approxeq(&self, other: &Self, _ulps: i64) -> bool { + self == other + } + + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:?} ({:x})", self, self) + } + } + )* + }; +} + +impl_integer_approxeq! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize } + +macro_rules! impl_float_approxeq { + { $($type:ty),* } => { + $( + impl ApproxEq for $type { + fn approxeq(&self, other: &Self, ulps: i64) -> bool { + if self.is_nan() && other.is_nan() { + true + } else { + (self.ulps(other) as i64).abs() <= ulps + } + } + + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:?} ({:x})", self, self.to_bits()) + } + } + )* + }; +} + +impl_float_approxeq! { f32, f64 } + +impl ApproxEq for [T; N] { + fn approxeq(&self, other: &Self, ulps: i64) -> bool { + self.iter() + .zip(other.iter()) + .fold(true, |value, (left, right)| { + value && left.approxeq(right, ulps) + }) + } + + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + #[repr(transparent)] + struct Wrapper<'a, T: ApproxEq>(&'a T); + + impl core::fmt::Debug for Wrapper<'_, T> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(f) + } + } + + f.debug_list() + .entries(self.iter().map(|x| Wrapper(x))) + .finish() + } +} + +#[doc(hidden)] +pub struct ApproxEqWrapper<'a, T>(pub &'a T, pub i64); + +impl PartialEq for ApproxEqWrapper<'_, T> { + fn eq(&self, other: &T) -> bool { + self.0.approxeq(other, self.1) + } +} + +impl core::fmt::Debug for ApproxEqWrapper<'_, T> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(f) + } +} + +#[macro_export] +macro_rules! prop_assert_approxeq { + { $a:expr, $b:expr, $ulps:expr $(,)? } => { + { + use $crate::approxeq::ApproxEqWrapper; + let a = $a; + let b = $b; + proptest::prop_assert_eq!(ApproxEqWrapper(&a, $ulps), b); + } + }; +} diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs index 197c920e11eac..eb3d3f68bc2ea 100644 --- a/crates/test_helpers/src/lib.rs +++ b/crates/test_helpers/src/lib.rs @@ -12,6 +12,9 @@ pub mod wasm; #[macro_use] pub mod biteq; +#[macro_use] +pub mod approxeq; + pub mod subnormals; use subnormals::FlushSubnormals; @@ -185,6 +188,41 @@ pub fn test_unary_elementwise( + fv: &dyn Fn(Vector) -> VectorResult, + fs: &dyn Fn(Scalar) -> ScalarResult, + check: &dyn Fn([Scalar; LANES]) -> bool, + ulps: i64, +) where + Scalar: Copy + core::fmt::Debug + DefaultStrategy, + ScalarResult: Copy + approxeq::ApproxEq + core::fmt::Debug + DefaultStrategy, + Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy, + VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy, +{ + test_1(&|x: [Scalar; LANES]| { + proptest::prop_assume!(check(x)); + let result_1: [ScalarResult; LANES] = fv(x.into()).into(); + let result_2: [ScalarResult; LANES] = x + .iter() + .copied() + .map(fs) + .collect::>() + .try_into() + .unwrap(); + crate::prop_assert_approxeq!(result_1, result_2, ulps); + Ok(()) + }); +} + /// Test a unary vector function against a unary scalar function, applied elementwise. /// /// Where subnormals are flushed, use approximate equality. @@ -290,6 +328,44 @@ pub fn test_binary_elementwise< }); } +/// Test a binary vector function against a binary scalar function, applied elementwise. +pub fn test_binary_elementwise_approx< + Scalar1, + Scalar2, + ScalarResult, + Vector1, + Vector2, + VectorResult, + const LANES: usize, +>( + fv: &dyn Fn(Vector1, Vector2) -> VectorResult, + fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult, + check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool, + ulps: i64, +) where + Scalar1: Copy + core::fmt::Debug + DefaultStrategy, + Scalar2: Copy + core::fmt::Debug + DefaultStrategy, + ScalarResult: Copy + approxeq::ApproxEq + core::fmt::Debug + DefaultStrategy, + Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy, + Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy, + VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy, +{ + test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| { + proptest::prop_assume!(check(x, y)); + let result_1: [ScalarResult; LANES] = fv(x.into(), y.into()).into(); + let result_2: [ScalarResult; LANES] = x + .iter() + .copied() + .zip(y.iter().copied()) + .map(|(x, y)| fs(x, y)) + .collect::>() + .try_into() + .unwrap(); + crate::prop_assert_approxeq!(result_1, result_2, ulps); + Ok(()) + }); +} + /// Test a binary vector function against a binary scalar function, applied elementwise. /// /// Where subnormals are flushed, use approximate equality. @@ -528,8 +604,6 @@ macro_rules! test_lanes { use super::*; fn implementation() - where - core_simd::simd::LaneCount<$lanes>: core_simd::simd::SupportedLaneCount, $body #[cfg(target_arch = "wasm32")] @@ -628,8 +702,6 @@ macro_rules! test_lanes_panic { use super::*; fn implementation() - where - core_simd::simd::LaneCount<$lanes>: core_simd::simd::SupportedLaneCount, $body // test some odd and even non-power-of-2 lengths on miri diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d17c6d2e88946..639d07df73374 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-01-16" +channel = "nightly-2026-01-26" components = ["rustfmt", "clippy", "miri", "rust-src"] From a4c0bf5edaec5bc09ef47f3b4bef6ace2a7c551a Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 2 Feb 2026 12:04:56 +0000 Subject: [PATCH 02/53] switch to v0 mangling by default on stable Following rust-lang/rust#89117, rustc has defaulted to the v0 mangling scheme by default (since Nov 20th 2025). This surfaced two bugs: - rust-lang/rust#138261 was a small ICE (found via fuzzing) where an implementation-internal namespace was missing for global assembly - this occurs with names instantiated within global assembly (that can happen inside constants) - rust-lang/rust#134479 only occurs with unstable `generic_const_exprs` Since there have been three-to-four months for users to find bugs with this mangling scheme on nightly, that the scheme has been waiting many years to be stabilised, and has been used successfully internally at Microsoft, Meta and Google for many years, this patch proposes stabilising the v0 mangling scheme on stable. This patch does not propose removing the legacy mangling, it will remain usable on nightly as an escape-hatch if there are remaining bugs (though admittedly it would require switching to nightly for those on stable) - it is anticipated that this would be unlikely given current testing undergone by v0. Legacy mangling can be removed in another follow-up. --- compiler/rustc_session/src/config.rs | 6 +----- compiler/rustc_session/src/options.rs | 2 +- src/bootstrap/src/core/builder/cargo.rs | 13 ++----------- src/doc/rustc/src/symbol-mangling/index.md | 7 +++---- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 5e2671ef4ef6b..8ebb5233f6c80 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1483,11 +1483,7 @@ impl Options { } pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { - self.cg.symbol_mangling_version.unwrap_or(if self.unstable_features.is_nightly_build() { - SymbolManglingVersion::V0 - } else { - SymbolManglingVersion::Legacy - }) + self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::V0) } #[inline] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9219b5a7e8aca..cd0dc97c97a59 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2194,7 +2194,7 @@ options! { "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"), + "which mangling version to use for symbol names ('legacy', 'v0' (default), or 'hashed')"), target_cpu: Option = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 7150b2b0d59f2..1d7285e7c7519 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -664,16 +664,6 @@ impl Builder<'_> { rustflags.arg(sysroot_str); } - let use_new_symbol_mangling = self.config.rust_new_symbol_mangling.or_else(|| { - if mode != Mode::Std { - // The compiler and tools default to the new scheme - Some(true) - } else { - // std follows the flag's default, which per compiler-team#938 is v0 on nightly - None - } - }); - // By default, windows-rs depends on a native library that doesn't get copied into the // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native // library unnecessary. This can be removed when windows-rs enables raw-dylib @@ -683,7 +673,8 @@ impl Builder<'_> { rustflags.arg("--cfg=windows_raw_dylib"); } - if let Some(usm) = use_new_symbol_mangling { + // When unset, follow the default of the compiler flag - the compiler, tools and std use v0 + if let Some(usm) = self.config.rust_new_symbol_mangling { rustflags.arg(if usm { "-Csymbol-mangling-version=v0" } else { diff --git a/src/doc/rustc/src/symbol-mangling/index.md b/src/doc/rustc/src/symbol-mangling/index.md index ad565da9746cb..3f7d55063ca6a 100644 --- a/src/doc/rustc/src/symbol-mangling/index.md +++ b/src/doc/rustc/src/symbol-mangling/index.md @@ -46,7 +46,6 @@ foo::example_function ## Mangling versions -`rustc` supports different mangling versions which encode the names in different ways. -The legacy version (which is currently the default on beta/stable) is not described here. -The "v0" mangling scheme addresses several limitations of the legacy format, -and is described in the [v0 Symbol Format](v0.md) chapter. +There is currently one stable mangling scheme version - `v0`. On nightly builds, rustc supports +switching back to the `legacy` mangling scheme using [`-C symbol-mangling-version`]. The `v0` +mangling scheme is described in the [v0 Symbol Format](v0.md) chapter. From c3ef307d1bc769136e8ce73453f8857f979a60e2 Mon Sep 17 00:00:00 2001 From: N1ark Date: Sun, 15 Mar 2026 22:41:07 +0000 Subject: [PATCH 03/53] Merge `fabsfN` into `fabs::` Add `bounds::FloatPrimitive` Exhaustive float pattern match Fix GCC use span bugs --- src/intrinsics/mod.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 8b112e695275a..780550fc4cc74 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -346,10 +346,6 @@ fn codegen_float_intrinsic_call<'tcx>( sym::log10f32 => ("log10f", 1, fx.tcx.types.f32, types::F32), sym::log10f64 => ("log10", 1, fx.tcx.types.f64, types::F64), sym::log10f128 => ("log10f128", 1, fx.tcx.types.f128, types::F128), - sym::fabsf16 => ("fabsf16", 1, fx.tcx.types.f16, types::F16), - sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32, types::F32), - sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64), - sym::fabsf128 => ("fabsf128", 1, fx.tcx.types.f128, types::F128), sym::fmaf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64), @@ -441,11 +437,7 @@ fn codegen_float_intrinsic_call<'tcx>( sym::copysignf32 | sym::copysignf64 => { CValue::by_val(fx.bcx.ins().fcopysign(args[0], args[1]), layout) } - sym::fabsf16 => CValue::by_val(codegen_f16_f128::abs_f16(fx, args[0]), layout), - sym::fabsf128 => CValue::by_val(codegen_f16_f128::abs_f128(fx, args[0]), layout), - sym::fabsf32 - | sym::fabsf64 - | sym::floorf32 + sym::floorf32 | sym::floorf64 | sym::ceilf32 | sym::ceilf64 @@ -456,7 +448,6 @@ fn codegen_float_intrinsic_call<'tcx>( | sym::sqrtf32 | sym::sqrtf64 => { let val = match intrinsic { - sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(args[0]), sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]), sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]), sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]), @@ -1179,6 +1170,28 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); } + sym::fabs => { + intrinsic_args!(fx, args => (arg); intrinsic); + let layout = arg.layout(); + let ty::Float(float_ty) = layout.ty.kind() else { + span_bug!( + source_info.span, + "expected float type for fabs intrinsic: {:?}", + layout.ty + ); + }; + let x = arg.load_scalar(fx); + let val = match float_ty { + FloatTy::F32 | FloatTy::F64 => fx.bcx.ins().fabs(x), + // FIXME(bytecodealliance/wasmtime#8312): Use `fabsf16` once Cranelift + // backend lowerings are implemented. + FloatTy::F16 => codegen_f16_f128::abs_f16(fx, x), + FloatTy::F128 => codegen_f16_f128::abs_f128(fx, x), + }; + let val = CValue::by_val(val, layout); + ret.write_cvalue(fx, val); + } + sym::minimumf16 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); From a3741b2aef6f557b9fb52a07e5d4ebda0ad8bd56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Mar 2026 15:04:47 +0100 Subject: [PATCH 04/53] simd_fmin/fmax: make semantics and name consistent with scalar intrinsics --- example/float-minmax-pass.rs | 16 ++++++++-------- src/intrinsics/simd.rs | 10 +++++++--- src/num.rs | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/example/float-minmax-pass.rs b/example/float-minmax-pass.rs index b7491b7e522f3..206c56e887c7d 100644 --- a/example/float-minmax-pass.rs +++ b/example/float-minmax-pass.rs @@ -33,24 +33,24 @@ fn main() { let n = f32x4([nan, nan, nan, nan]); unsafe { - let min0 = simd_fmin(x, y); - let min1 = simd_fmin(y, x); + let min0 = simd_minimum_number_nsz(x, y); + let min1 = simd_minimum_number_nsz(y, x); assert_eq!(min0.into_array(), min1.into_array()); let e = f32x4([1.0, 1.0, 3.0, 3.0]); assert_eq!(min0.into_array(), e.into_array()); - let minn = simd_fmin(x, n); + let minn = simd_minimum_number_nsz(x, n); assert_eq!(minn.into_array(), x.into_array()); - let minn = simd_fmin(y, n); + let minn = simd_minimum_number_nsz(y, n); assert_eq!(minn.into_array(), y.into_array()); - let max0 = simd_fmax(x, y); - let max1 = simd_fmax(y, x); + let max0 = simd_maximum_number_nsz(x, y); + let max1 = simd_maximum_number_nsz(y, x); assert_eq!(max0.into_array(), max1.into_array()); let e = f32x4([2.0, 2.0, 4.0, 4.0]); assert_eq!(max0.into_array(), e.into_array()); - let maxn = simd_fmax(x, n); + let maxn = simd_maximum_number_nsz(x, n); assert_eq!(maxn.into_array(), x.into_array()); - let maxn = simd_fmax(y, n); + let maxn = simd_maximum_number_nsz(y, n); assert_eq!(maxn.into_array(), y.into_array()); } } diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 200cedf0f6ae0..cc2311a67b5d5 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -493,7 +493,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } - sym::simd_fmin | sym::simd_fmax => { + sym::simd_minimum_number_nsz | sym::simd_maximum_number_nsz => { intrinsic_args!(fx, args => (x, y); intrinsic); if !x.layout().ty.is_simd() { @@ -508,8 +508,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _ => unreachable!("{:?}", lane_ty), } match intrinsic { - sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane), - sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane), + sym::simd_minimum_number_nsz => { + crate::num::codegen_float_min(fx, x_lane, y_lane) + } + sym::simd_maximum_number_nsz => { + crate::num::codegen_float_max(fx, x_lane, y_lane) + } _ => unreachable!(), } }); diff --git a/src/num.rs b/src/num.rs index 0459644e16aa7..e583f3f2f754a 100644 --- a/src/num.rs +++ b/src/num.rs @@ -500,8 +500,8 @@ fn codegen_ptr_binop<'tcx>( // In Rust floating point min and max don't propagate NaN (not even SNaN). In Cranelift they do // however. For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for -// `minnumf*` and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by -// comparing a float against itself. Only in case of NaN is it not equal to itself. +// `minimum_number_nsz` and `a.is_nan() ? b : (a <= b ? b : a)` for `maximum_number_nsz`. NaN checks +// are done by comparing a float against itself. Only in case of NaN is it not equal to itself. pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once // `f16`/`f128` backend lowerings have been added to Cranelift. From e33d70223e372bd93d76934242617e413a4cdcbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Mar 2026 15:04:47 +0100 Subject: [PATCH 05/53] simd_fmin/fmax: make semantics and name consistent with scalar intrinsics --- crates/core_simd/src/simd/num/float.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index efd7c2469512b..175cbce4f58be 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -385,13 +385,13 @@ macro_rules! impl_trait { #[inline] fn simd_min(self, other: Self) -> Self { // Safety: `self` and `other` are float vectors - unsafe { core::intrinsics::simd::simd_fmin(self, other) } + unsafe { core::intrinsics::simd::simd_minimum_number_nsz(self, other) } } #[inline] fn simd_max(self, other: Self) -> Self { // Safety: `self` and `other` are floating point vectors - unsafe { core::intrinsics::simd::simd_fmax(self, other) } + unsafe { core::intrinsics::simd::simd_maximum_number_nsz(self, other) } } #[inline] From 9a925322aca86a828c5515c4f92b94e436210e29 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:43:04 +0100 Subject: [PATCH 06/53] Merge commit '493d427c7d3423f085f05179e36a35b4943b1379' into sync_cg_clif-2026-03-25 --- .github/workflows/abi-cafe.yml | 4 +- .github/workflows/audit.yml | 18 --- .github/workflows/main.yml | 32 ++-- .github/workflows/rustc.yml | 8 +- Cargo.lock | 142 ++++++++++-------- Cargo.toml | 28 ++-- build_system/main.rs | 9 +- build_system/todo.rs | 70 +++++++++ build_system/usage.txt | 1 + clean_all.sh | 6 - example/mini_core.rs | 4 +- example/mini_core_hello_world.rs | 12 +- example/neon.rs | 2 +- example/std_example.rs | 100 ++++++++++-- ...0027-stdlib-128bit-atomic-operations.patch | 13 +- rust-toolchain.toml | 2 +- scripts/setup_rust_fork.sh | 18 +-- scripts/test_rustc_tests.sh | 2 - src/global_asm.rs | 16 +- src/inline_asm.rs | 112 ++++++++------ 20 files changed, 386 insertions(+), 213 deletions(-) delete mode 100644 .github/workflows/audit.yml create mode 100644 build_system/todo.rs diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index 3367562f26838..c11fc5921ef11 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -43,7 +43,7 @@ jobs: # TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features if: matrix.os == 'ubuntu-latest' @@ -56,7 +56,7 @@ jobs: run: .github/scripts/free-disk-space.sh - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml deleted file mode 100644 index 95a4dcd3266df..0000000000000 --- a/.github/workflows/audit.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Security audit -on: - workflow_dispatch: - schedule: - - cron: '0 10 * * 1' # every monday at 10:00 UTC -permissions: - issues: write - checks: write -jobs: - audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: | - sed -i 's/components.*/components = []/' rust-toolchain.toml - - uses: rustsec/audit-check@v2.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 07d9af4a9b54a..7f9fd0cc7c5e0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,12 +19,22 @@ env: RUSTFLAGS: "-Dwarnings" jobs: + todo_check: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v6 + + - name: Check todo + run: ./y.sh check-todo + rustfmt: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Avoid installing rustc-dev run: | @@ -78,14 +88,14 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features if: matrix.os == 'ubuntu-latest' run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} @@ -127,7 +137,7 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo @@ -149,13 +159,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} @@ -201,10 +211,10 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} @@ -223,7 +233,7 @@ jobs: run: tar cvfJ cg_clif.tar.xz dist - name: Upload prebuilt cg_clif - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz @@ -232,7 +242,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/main' }} - needs: [rustfmt, test, bench, dist] + needs: [todo_check, rustfmt, test, bench, dist] permissions: contents: write # for creating the dev tag and release @@ -242,7 +252,7 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Download all built artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index b22725fdc9d41..0f91bc11753eb 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -11,13 +11,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} @@ -31,13 +31,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/cg_clif key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} diff --git a/Cargo.lock b/Cargo.lock index afc1d0d0ab959..2d84d2c57fc6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" dependencies = [ "allocator-api2", ] @@ -43,42 +43,46 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cranelift-assembler-x64" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0377b13bf002a0774fcccac4f1102a10f04893d24060cf4b7350c87e4cbb647c" +checksum = "4f248321c6a7d4de5dcf2939368e96a397ad3f53b6a076e38d0104d1da326d37" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa027979140d023b25bf7509fb7ede3a54c3d3871fb5ead4673c4b633f671a2" +checksum = "ab6d78ff1f7d9bf8b7e1afbedbf78ba49e38e9da479d4c8a2db094e22f64e2bc" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618e4da87d9179a70b3c2f664451ca8898987aa6eb9f487d16988588b5d8cc40" +checksum = "6b6005ba640213a5b95382aeaf6b82bf028309581c8d7349778d66f27dc1180b" dependencies = [ "cranelift-entity", + "wasmtime-internal-core", ] [[package]] name = "cranelift-bitset" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db53764b5dad233b37b8f5dc54d3caa9900c54579195e00f17ea21f03f71aaa7" +checksum = "81fb5b134a12b559ff0c0f5af0fcd755ad380723b5016c4e0d36f74d39485340" +dependencies = [ + "wasmtime-internal-core", +] [[package]] name = "cranelift-codegen" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae927f1d8c0abddaa863acd201471d56e7fc6c3925104f4861ed4dc3e28b421" +checksum = "85837de8be7f17a4034a6b08816f05a3144345d2091937b39d415990daca28f4" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -90,21 +94,22 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown", + "hashbrown 0.16.1", + "libm", "log", "regalloc2", "rustc-hash", "serde", "smallvec", "target-lexicon", - "wasmtime-internal-math", + "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen-meta" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fcf1e3e6757834bd2584f4cbff023fcc198e9279dcb5d684b4bb27a9b19f54" +checksum = "e433faa87d38e5b8ff469e44a26fea4f93e58abd7a7c10bad9810056139700c9" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -114,33 +119,34 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "205dcb9e6ccf9d368b7466be675ff6ee54a63e36da6fe20e72d45169cf6fd254" +checksum = "5397ba61976e13944ca71230775db13ee1cb62849701ed35b753f4761ed0a9b7" [[package]] name = "cranelift-control" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "108eca9fcfe86026054f931eceaf57b722c1b97464bf8265323a9b5877238817" +checksum = "cc81c88765580720eb30f4fc2c1bfdb75fcbf3094f87b3cd69cecca79d77a245" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d96496910065d3165f84ff8e1e393916f4c086f88ac8e1b407678bc78735aa" +checksum = "463feed5d46cf8763f3ba3045284cf706dd161496e20ec9c14afbb4ba09b9e66" dependencies = [ "cranelift-bitset", + "wasmtime-internal-core", ] [[package]] name = "cranelift-frontend" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e303983ad7e23c850f24d9c41fc3cb346e1b930f066d3966545e4c98dac5c9fb" +checksum = "a4c5eca7696c1c04ab4c7ed8d18eadbb47d6cc9f14ec86fe0881bf1d7e97e261" dependencies = [ "cranelift-codegen", "log", @@ -150,15 +156,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b0cf8d867d891245836cac7abafb0a5b0ea040a019d720702b3b8bcba40bfa" +checksum = "f1153844610cc9c6da8cf10ce205e45da1a585b7688ed558aa808bbe2e4e6d77" [[package]] name = "cranelift-jit" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf1e35da6eca2448395f483eb172ce71dd7842f7dc96f44bb8923beafe43c6d" +checksum = "41836de8321b303d3d4188e58cc09c30c7645337342acfcfb363732695cae098" dependencies = [ "anyhow", "cranelift-codegen", @@ -176,9 +182,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "792ba2a54100e34f8a36e3e329a5207cafd1f0918a031d34695db73c163fdcc7" +checksum = "b731f66cb1b69b60a74216e632968ebdbb95c488d26aa1448ec226ae0ffec33e" dependencies = [ "anyhow", "cranelift-codegen", @@ -187,9 +193,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24b641e315443e27807b69c440fe766737d7e718c68beb665a2d69259c77bf3" +checksum = "a97b583fe9a60f06b0464cee6be5a17f623fd91b217aaac99b51b339d19911af" dependencies = [ "cranelift-codegen", "libc", @@ -198,9 +204,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecba1f219a201cf946150538e631defd620c5051b62c52ecb89a0004bab263d4" +checksum = "9809d2d419cd18f17377f4ce64a7ad22eeda0d042c08833d3796657f1ddebc82" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +219,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.128.3" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e378a54e7168a689486d67ee1f818b7e5356e54ae51a1d7a53f4f13f7f8b7a" +checksum = "8594dc6bb4860fa8292f1814c76459dbfb933e1978d8222de6380efce45c7cee" [[package]] name = "crc32fast" @@ -233,24 +239,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "fallible-iterator" -version = "0.3.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "gimli" -version = "0.32.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" dependencies = [ - "fallible-iterator", + "fnv", + "hashbrown 0.16.1", "indexmap", "stable_deref_trait", ] @@ -260,6 +267,12 @@ name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "foldhash", ] @@ -272,12 +285,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -325,12 +338,12 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "object" -version = "0.37.3" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" dependencies = [ "crc32fast", - "hashbrown", + "hashbrown 0.16.1", "indexmap", "memchr", ] @@ -355,13 +368,13 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.13.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" +checksum = "952ddbfc6f9f64d006c3efd8c9851a6ba2f2b944ba94730db255d55006e0ffda" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown", + "hashbrown 0.15.5", "log", "rustc-hash", "smallvec", @@ -468,24 +481,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] -name = "wasmtime-internal-jit-icache-coherence" -version = "41.0.3" +name = "wasmtime-internal-core" +version = "43.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bada5ca1cc47df7d14100e2254e187c2486b426df813cea2dd2553a7469f7674" +checksum = "e671917bb6856ae360cb59d7aaf26f1cfd042c7b924319dd06fd380739fc0b2e" dependencies = [ - "anyhow", - "cfg-if", - "libc", - "windows-sys 0.61.2", + "hashbrown 0.16.1", + "libm", ] [[package]] -name = "wasmtime-internal-math" -version = "41.0.3" +name = "wasmtime-internal-jit-icache-coherence" +version = "43.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6f615d528eda9adc6eefb062135f831b5215c348f4c3ec3e143690c730605b" +checksum = "9b3112806515fac8495883885eb8dbdde849988ae91fe6beb544c0d7c0f4c9aa" dependencies = [ - "libm", + "cfg-if", + "libc", + "wasmtime-internal-core", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a7b4664282eda..6707557f06f75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.128.3", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.128.3" } -cranelift-module = { version = "0.128.3" } -cranelift-native = { version = "0.128.3" } -cranelift-jit = { version = "0.128.3", optional = true } -cranelift-object = { version = "0.128.3" } +cranelift-codegen = { version = "0.130.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.130.0" } +cranelift-module = { version = "0.130.0" } +cranelift-native = { version = "0.130.0" } +cranelift-jit = { version = "0.130.0", optional = true } +cranelift-object = { version = "0.130.0" } target-lexicon = "0.13" -gimli = { version = "0.32", default-features = false, features = ["write"] } -object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.33", default-features = false, features = ["write"] } +object = { version = "0.38.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.9.0", optional = true } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/build_system/main.rs b/build_system/main.rs index 6251687babc67..0720d72c6d7cb 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -17,6 +17,7 @@ mod prepare; mod rustc_info; mod shared_utils; mod tests; +mod todo; mod utils; fn usage() { @@ -38,6 +39,7 @@ enum Command { Test, AbiCafe, Bench, + CheckTodo, } #[derive(Copy, Clone, Debug)] @@ -66,6 +68,7 @@ fn main() { Some("test") => Command::Test, Some("abi-cafe") => Command::AbiCafe, Some("bench") => Command::Bench, + Some("check-todo") => Command::CheckTodo, Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag), Some(command) => arg_error!("Unknown command {}", command), None => { @@ -139,6 +142,10 @@ fn main() { process::exit(0); } + if command == Command::CheckTodo { + todo::run(); + } + let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) { (Ok(_), Ok(_), Ok(_)) => None, (_, Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()), @@ -202,7 +209,7 @@ fn main() { )) }; match command { - Command::Prepare => { + Command::Prepare | Command::CheckTodo => { // Handled above } Command::Test => { diff --git a/build_system/todo.rs b/build_system/todo.rs new file mode 100644 index 0000000000000..66b31a10a065d --- /dev/null +++ b/build_system/todo.rs @@ -0,0 +1,70 @@ +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::{fs, process}; + +const EXTENSIONS: &[&str] = + &["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"]; + +fn has_supported_extension(path: &Path) -> bool { + path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e))) +} + +fn list_tracked_files() -> Result, String> { + let output = Command::new("git") + .args(["ls-files", "-z"]) + .output() + .map_err(|e| format!("Failed to run `git ls-files`: {e}"))?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(format!("`git ls-files` failed: {stderr}")); + } + + let mut files = Vec::new(); + for entry in output.stdout.split(|b| *b == 0) { + if entry.is_empty() { + continue; + } + let path = std::str::from_utf8(entry).unwrap(); + files.push(PathBuf::from(path)); + } + + Ok(files) +} + +pub(crate) fn run() -> ! { + let files = list_tracked_files().unwrap(); + let mut error_count = 0; + // Avoid embedding the task marker in source so greps only find real occurrences. + let todo_marker = "todo".to_ascii_uppercase(); + + for file in files { + if !has_supported_extension(&file) { + continue; + } + + let bytes = fs::read(&file).unwrap(); + let contents = std::str::from_utf8(&bytes).unwrap(); + + for (i, line) in contents.split('\n').enumerate() { + let trimmed = line.trim(); + if trimmed.contains(&todo_marker) { + eprintln!( + "{}:{}: {} is used for tasks that should be done before merging a PR; if you want to leave a message in the codebase use FIXME", + file.display(), + i + 1, + todo_marker + ); + error_count += 1; + } + } + } + + if error_count == 0 { + process::exit(0); + } + + eprintln!("found {} {}(s)", error_count, todo_marker); + process::exit(1); +} diff --git a/build_system/usage.txt b/build_system/usage.txt index 6c98087e52399..572fe78058101 100644 --- a/build_system/usage.txt +++ b/build_system/usage.txt @@ -6,6 +6,7 @@ USAGE: ./y.sh test [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME] ./y.sh abi-cafe [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] ./y.sh bench [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] + ./y.sh check-todo OPTIONS: --sysroot none|clif|llvm diff --git a/clean_all.sh b/clean_all.sh index 4dbd9dac94a89..32ed19300ac6a 100755 --- a/clean_all.sh +++ b/clean_all.sh @@ -2,9 +2,3 @@ set -e rm -rf target/ build_system/target download/ build/ dist/ - -# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh -# FIXME remove at some point in the future -rm y.bin y.bin.dSYM y.exe y.pdb 2>/dev/null || true -rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/ -rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} diff --git a/example/mini_core.rs b/example/mini_core.rs index 5293b458d8c4f..218050982e6d3 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -9,9 +9,9 @@ rustc_private, transparent_unions, auto_traits, - freeze_impls, - thread_local + freeze_impls )] +#![cfg_attr(not(all(windows, target_env = "gnu")), feature(thread_local))] #![no_core] #![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)] diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 10549cd2a41e2..6734d19fbb48b 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -1,13 +1,5 @@ -#![feature( - no_core, - lang_items, - never_type, - linkage, - extern_types, - thread_local, - repr_simd, - rustc_private -)] +#![feature(no_core, lang_items, never_type, extern_types, thread_local, repr_simd, rustc_private)] +#![cfg_attr(not(any(jit, target_vendor = "apple", windows)), feature(linkage))] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] diff --git a/example/neon.rs b/example/neon.rs index fb3e10a41c025..98a2a7af38f6b 100644 --- a/example/neon.rs +++ b/example/neon.rs @@ -1,6 +1,6 @@ // Most of these tests are copied from https://github.com/japaric/stdsimd/blob/0f4413d01c4f0c3ffbc5a69e9a37fbc7235b31a9/coresimd/arm/neon.rs -#![feature(portable_simd)] +#![cfg_attr(target_arch = "aarch64", feature(portable_simd))] #[cfg(target_arch = "aarch64")] use std::arch::aarch64::*; diff --git a/example/std_example.rs b/example/std_example.rs index 33db75f0943a9..f0e38ae0610c9 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -1,14 +1,8 @@ -#![feature( - core_intrinsics, - coroutines, - stmt_expr_attributes, - coroutine_trait, - repr_simd, - tuple_trait, - unboxed_closures -)] +#![feature(core_intrinsics, coroutines, coroutine_trait, repr_simd, tuple_trait, unboxed_closures)] #![allow(internal_features)] +#[cfg(target_arch = "x86_64")] +use std::arch::asm; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; use std::hint::black_box; @@ -173,6 +167,9 @@ fn main() { rust_call_abi(); + // #[cfg(target_arch = "x86_64")] + // inline_asm_call_custom_abi(); + const fn no_str() -> Option> { None } @@ -279,6 +276,17 @@ unsafe fn test_simd() { #[cfg(not(jit))] test_crc32(); + + #[cfg(not(jit))] + test_xmm_roundtrip(); + #[cfg(not(jit))] + if is_x86_feature_detected!("avx") { + test_ymm_roundtrip(); + } + #[cfg(not(jit))] + if is_x86_feature_detected!("avx512f") { + test_zmm_roundtrip(); + } } } @@ -576,6 +584,65 @@ unsafe fn test_mm_cvtps_ph() { assert_eq_m128i(r, e); } +#[cfg(target_arch = "x86_64")] +#[cfg(not(jit))] +unsafe fn test_xmm_roundtrip() { + unsafe { + let input = [1u8; 16]; + let mut output = [0u8; 16]; + + asm!( + "movups {xmm}, [{input}]", + "movups [{output}], {xmm}", + input = in(reg) input.as_ptr(), + output = in(reg) output.as_mut_ptr(), + xmm = out(xmm_reg) _, + ); + + assert_eq!(input, output); + } +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx")] +#[cfg(not(jit))] +unsafe fn test_ymm_roundtrip() { + unsafe { + let input = [1u8; 32]; + let mut output = [0u8; 32]; + + asm!( + "vmovups {ymm}, [{input}]", + "vmovups [{output}], {ymm}", + input = in(reg) input.as_ptr(), + output = in(reg) output.as_mut_ptr(), + ymm = out(ymm_reg) _, + ); + + assert_eq!(input, output); + } +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx512f")] +#[cfg(not(jit))] +unsafe fn test_zmm_roundtrip() { + unsafe { + let input = [1u8; 64]; + let mut output = [0u8; 64]; + + asm!( + "vmovups {zmm}, [{input}]", + "vmovups [{output}], {zmm}", + input = in(reg) input.as_ptr(), + output = in(reg) output.as_mut_ptr(), + zmm = out(zmm_reg) _, + ); + + assert_eq!(input, output); + } +} + fn test_checked_mul() { let u: Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); @@ -614,3 +681,18 @@ fn map(a: Option<(u8, Box)>) -> Option> { Some((_, instr)) => Some(instr), } } + +// FIXME enable once inline asm sym references are stabilized in cg_clif +// #[cfg(target_arch = "x86_64")] +// fn inline_asm_call_custom_abi() { +// use std::arch::{asm, naked_asm}; +// +// #[unsafe(naked)] +// unsafe extern "custom" fn double() { +// naked_asm!("add rax, rax", "ret"); +// } +// +// let mut x: u64 = 21; +// unsafe { asm!("call {}", sym double, inout("rax") x) }; +// assert_eq!(x, 42); +// } diff --git a/patches/0027-stdlib-128bit-atomic-operations.patch b/patches/0027-stdlib-128bit-atomic-operations.patch index 38bb43f8204b4..b7276e43153bc 100644 --- a/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/patches/0027-stdlib-128bit-atomic-operations.patch @@ -37,16 +37,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index bf2b6d59f88..d5ccce03bbf 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -300,8 +300,6 @@ impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4)); - impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4)); - impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8)); - impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8)); --impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16)); --impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16)); - - #[cfg(target_pointer_width = "16")] - impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2)); -@@ -3585,44 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { +@@ -3585,42 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { 8, u64 AtomicU64 } @@ -62,7 +53,6 @@ index bf2b6d59f88..d5ccce03bbf 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- rustc_diagnostic_item = "AtomicI128", - "i128", - "#![feature(integer_atomics)]\n\n", - atomic_min, atomic_max, @@ -81,7 +71,6 @@ index bf2b6d59f88..d5ccce03bbf 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- rustc_diagnostic_item = "AtomicU128", - "u128", - "#![feature(integer_atomics)]\n\n", - atomic_umin, atomic_umax, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index fe967c84352c8..d4bb9bea82bb5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-02-18" +channel = "nightly-2026-03-25" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index bb9f69b5c9744..2ca0c3cab910f 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -63,18 +63,18 @@ index 2e16f2cf27..3ac3df99a8 100644 # Note that RUSTFLAGS_BOOTSTRAP should always be added to the end of # RUSTFLAGS, since that causes RUSTFLAGS_BOOTSTRAP to override RUSTFLAGS. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs -index a656927b1f6..44fc5546fac 100644 +index bc68bfe396..00143ef3ed 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs -@@ -2249,7 +2249,7 @@ pub fn parse_download_ci_llvm<'a>( - } +@@ -2230,7 +2230,7 @@ pub fn download_ci_rustc_commit<'a>( + return None; + } - #[cfg(not(test))] -- if b && dwn_ctx.is_running_on_ci && CiEnv::is_rust_lang_managed_ci_job() { -+ if false && dwn_ctx.is_running_on_ci && CiEnv::is_rust_lang_managed_ci_job() { - // On rust-lang CI, we must always rebuild LLVM if there were any modifications to it - panic!( - "\`llvm.download-ci-llvm\` cannot be set to \`true\` on CI. Use \`if-unchanged\` instead." +- if dwn_ctx.is_running_on_ci() { ++ if false && dwn_ctx.is_running_on_ci() { + eprintln!("CI rustc commit matches with HEAD and we are in CI."); + eprintln!( + "\`rustc.download-ci\` functionality will be skipped as artifacts are not available." diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 330fb465de..a4593ed96f 100644 --- a/src/build_helper/src/git.rs diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 8712b41c8f8f6..71ff4eef071c3 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -20,7 +20,6 @@ for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|//@ error-pa done git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed -git checkout -- tests/ui/proc-macro/pretty-print-hack/ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs # missing features @@ -152,7 +151,6 @@ rm -r tests/run-make/short-ice # ICE backtrace begin/end marker mismatch rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump rm -r tests/run-make/strip # same rm -r tests/run-make-cargo/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source -rm -r tests/run-make/translation # same rm -r tests/run-make-cargo/panic-immediate-abort-works # same rm -r tests/run-make-cargo/panic-immediate-abort-codegen # same rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features diff --git a/src/global_asm.rs b/src/global_asm.rs index 1daf428acf766..b14988577845f 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -120,9 +120,15 @@ fn codegen_global_asm_inner<'tcx>( } let symbol = tcx.symbol_name(instance); + let symbol_name = if tcx.sess.target.is_like_darwin { + format!("_{}", symbol.name) + } else { + symbol.name.to_owned() + }; + // FIXME handle the case where the function was made private to the // current codegen unit - global_asm.push_str(&escape_symbol_name(tcx, symbol.name, span)); + global_asm.push_str(&escape_symbol_name(tcx, &symbol_name, span)); } GlobalAsmOperandRef::SymStatic { def_id } => { if cfg!(not(feature = "inline_asm_sym")) { @@ -134,7 +140,13 @@ fn codegen_global_asm_inner<'tcx>( let instance = Instance::mono(tcx, def_id); let symbol = tcx.symbol_name(instance); - global_asm.push_str(&escape_symbol_name(tcx, symbol.name, span)); + let symbol_name = if tcx.sess.target.is_like_darwin { + format!("_{}", symbol.name) + } else { + symbol.name.to_owned() + }; + + global_asm.push_str(&escape_symbol_name(tcx, &symbol_name, span)); } } } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index ac0da06cbb8e3..8100d565b3974 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -3,8 +3,10 @@ use std::fmt::Write; use cranelift_codegen::isa::CallConv; +use rustc_abi::CanonAbi; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::LangItem; +use rustc_middle::ty::layout::FnAbiOf; use rustc_span::sym; use rustc_target::asm::*; use rustc_target::spec::Arch; @@ -120,21 +122,30 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( .unwrap(); let symbol = fx.tcx.symbol_name(instance); - // Pass a wrapper rather than the function itself as the function itself may not - // be exported from the main codegen unit and may thus be unreachable from the - // object file created by an external assembler. - let wrapper_name = format!( - "{}__inline_asm_{}_wrapper_n{}", - fx.symbol_name, - fx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - fx.inline_asm_index, - ); - fx.inline_asm_index += 1; - let sig = - get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); - create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); - - CInlineAsmOperand::Symbol { symbol: wrapper_name } + if FullyMonomorphizedLayoutCx(fx.tcx) + .fn_abi_of_instance(instance, ty::List::empty()) + .conv + == CanonAbi::Custom + { + // We can't create a wrapper for custom ABI functions. + CInlineAsmOperand::Symbol { symbol: symbol.name.to_owned() } + } else { + // Pass a wrapper rather than the function itself as the function itself may not + // be exported from the main codegen unit and may thus be unreachable from the + // object file created by an external assembler. + let wrapper_name = format!( + "{}__inline_asm_{}_wrapper_n{}", + fx.symbol_name, + fx.cgu_name.as_str().replace('.', "__").replace('-', "_"), + fx.inline_asm_index, + ); + fx.inline_asm_index += 1; + let sig = + get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); + create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); + + CInlineAsmOperand::Symbol { symbol: wrapper_name } + } } else { span_bug!(span, "invalid type for asm sym (fn)"); } @@ -548,22 +559,21 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { match self.arch { InlineAsmArch::X86_64 => match reg { InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + if matches!( + reg.reg_class(), + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg + ) => { - // rustc emits x0 rather than xmm0 - let class = match *modifier { - None | Some('x') => "xmm", - Some('y') => "ymm", - Some('z') => "zmm", - _ => unreachable!(), - }; - write!( - generated_asm, - "{class}{}", - reg as u32 - X86InlineAsmReg::xmm0 as u32 - ) - .unwrap(); + // rustc emits x0/y0/z0 rather than xmm0/ymm0/zmm0 + let name = reg.name(); + if let Some(prefix) = modifier { + let index = &name[3..]; + write!(generated_asm, "{prefix}mm{index}").unwrap(); + } else { + write!(generated_asm, "{name}").unwrap(); + } } _ => reg .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) @@ -575,7 +585,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); } - CInlineAsmOperand::Symbol { ref symbol } => generated_asm.push_str(symbol), + CInlineAsmOperand::Symbol { ref symbol } => { + if binary_format == BinaryFormat::Macho { + generated_asm.push('_'); + } + + generated_asm.push_str(symbol); + } } } } @@ -716,12 +732,17 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { InlineAsmArch::X86_64 => { match reg { InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + if matches!( + reg.reg_class(), + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg + ) => { - // rustc emits x0 rather than xmm0 - write!(generated_asm, " movups [rbx+0x{:x}], ", offset.bytes()).unwrap(); - write!(generated_asm, "xmm{}", reg as u32 - X86InlineAsmReg::xmm0 as u32) + // rustc emits x0/y0/z0 rather than xmm0/ymm0/zmm0 + let name = reg.name(); + let mov = if name.starts_with("xmm") { "movups" } else { "vmovups" }; + write!(generated_asm, " {mov} [rbx+0x{:x}], {name}", offset.bytes()) .unwrap(); } _ => { @@ -761,16 +782,17 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { InlineAsmArch::X86_64 => { match reg { InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + if matches!( + reg.reg_class(), + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg + ) => { - // rustc emits x0 rather than xmm0 - write!( - generated_asm, - " movups xmm{}", - reg as u32 - X86InlineAsmReg::xmm0 as u32 - ) - .unwrap(); + // rustc emits x0/y0/z0 rather than xmm0/ymm0/zmm0 + let name = reg.name(); + let mov = if name.starts_with("xmm") { "movups" } else { "vmovups" }; + write!(generated_asm, " {mov} {name}").unwrap(); } _ => { generated_asm.push_str(" mov "); From 035bf6e39cd24b9232338ebd07fbf068fd809b7c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:55:32 +0100 Subject: [PATCH 07/53] Update exclusion list in build_llvm_sysroot_for_triple --- build_system/build_sysroot.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 5205ec1e8aaa1..7185e8326237b 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -178,9 +178,7 @@ fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { && !file_name_str.contains("rustc_std_workspace_") && !file_name_str.contains("rustc_demangle") && !file_name_str.contains("rustc_literal_escaper")) - || file_name_str.contains("chalk") - || file_name_str.contains("tracing") - || file_name_str.contains("regex") + || file_name_str.contains("LLVM") { // These are large crates that are part of the rustc-dev component and are not // necessary to run regular programs. From ea7f582d4e6e98d1a09f07dc4d8489099df883cc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:57:02 +0100 Subject: [PATCH 08/53] Use -Zbuild-dir-new-layout This will become the default soon. --- build_system/build_sysroot.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 7185e8326237b..216c87f095533 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -206,9 +206,9 @@ fn build_clif_sysroot_for_triple( apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); - // Cleanup the deps dir, but keep build scripts and the incremental cache for faster - // recompilation as they are not affected by changes in cg_clif. - ensure_empty_dir(&build_dir.join("deps")); + // Cleanup the build dir, but keep the incremental cache for faster + // recompilation as it is not affected by changes in cg_clif. + ensure_empty_dir(&build_dir.join("build")); } // Build sysroot @@ -241,6 +241,7 @@ fn build_clif_sysroot_for_triple( build_cmd.arg("--features").arg("backtrace panic-unwind"); build_cmd.arg(format!("-Zroot-dir={}", STDLIB_SRC.to_path(dirs).display())); build_cmd.arg("-Zno-embed-metadata"); + build_cmd.arg("-Zbuild-dir-new-layout"); build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true"); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); if compiler.triple.contains("apple") { @@ -252,7 +253,13 @@ fn build_clif_sysroot_for_triple( } spawn_and_wait(build_cmd); - for entry in fs::read_dir(build_dir.join("deps")).unwrap() { + for entry in fs::read_dir(build_dir.join("build")) + .unwrap() + .flat_map(|entry| entry.unwrap().path().read_dir().unwrap()) + .map(|entry| entry.unwrap().path().join("out")) + .filter(|entry| entry.exists()) + .flat_map(|entry| entry.read_dir().unwrap()) + { let entry = entry.unwrap(); if let Some(ext) = entry.path().extension() { if ext == "d" || ext == "dSYM" || ext == "clif" { From 90b98b249da08be987caed58d43401d4a450f9b6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 31 Mar 2026 18:50:03 +1100 Subject: [PATCH 09/53] Use `Hcx`/`hcx` consistently for `StableHashingContext`. The `HashStable` and `ToStableHashKey` traits both have a type parameter that is sometimes called `CTX` and sometimes called `HCX`. (In practice this type parameter is always instantiated as `StableHashingContext`.) Similarly, variables with these types are sometimes called `ctx` and sometimes called `hcx`. This inconsistency has bugged me for some time. The `HCX`/`hcx` form is more informative (the `H`/`h` indicates what type of context it is) and it matches other cases like `tcx`, `dcx`, `icx`. Also, RFC 430 says that type parameters should have names that are "concise UpperCamelCase, usually single uppercase letter: T". In this case `H` feels insufficient, and `Hcx` feels better. Therefore, this commit changes the code to use `Hcx`/`hcx` everywhere. --- src/driver/aot.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 79a3214568082..b855e1fa4b780 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -45,8 +45,8 @@ enum OngoingModuleCodegen { Async(JoinHandle>), } -impl HashStable for OngoingModuleCodegen { - fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { +impl HashStable for OngoingModuleCodegen { + fn hash_stable(&self, _: &mut Hcx, _: &mut StableHasher) { // do nothing } } From 85e5a244a517a5cd72f7bd1ec0003be46a460887 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Mar 2026 21:41:44 +1100 Subject: [PATCH 10/53] Use closures more consistently in `dep_graph.rs`. This file has several methods that take a `FnOnce() -> R` closure: - `DepGraph::with_ignore` - `DepGraph::with_query_deserialization` - `DepGraph::with_anon_task` - `DepGraphData::with_anon_task_inner` It also has two methods that take a faux closure via an `A` argument and a `fn(TyCtxt<'tcx>, A) -> R` argument: - DepGraph::with_task - DepGraphData::with_task The rationale is that the faux closure exercises tight control over what state they have access to. This seems silly when (a) they are passed a `TyCtxt`, and (b) when similar nearby functions take real closures. And they are more awkward to use, e.g. requiring multiple arguments to be gathered into a tuple. This commit changes the faux closures to real closures. --- src/driver/aot.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 79a3214568082..012d8caec16f8 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -380,11 +380,9 @@ fn codegen_cgu_content( fn module_codegen( tcx: TyCtxt<'_>, - (global_asm_config, cgu_name, token): ( - Arc, - rustc_span::Symbol, - ConcurrencyLimiterToken, - ), + global_asm_config: Arc, + cgu_name: rustc_span::Symbol, + token: ConcurrencyLimiterToken, ) -> OngoingModuleCodegen { let mut module = make_module(tcx.sess, cgu_name.as_str().to_string()); @@ -513,8 +511,14 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { let (module, _) = tcx.dep_graph.with_task( dep_node, tcx, - (global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())), - module_codegen, + || { + module_codegen( + tcx, + global_asm_config.clone(), + cgu.name(), + concurrency_limiter.acquire(tcx.dcx()), + ) + }, Some(rustc_middle::dep_graph::hash_result), ); IntoDynSyncSend(module) From adb7c3f538e0510a6cc434a2883d7679b014d891 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:52:35 +0200 Subject: [PATCH 11/53] Rustup to rustc 1.96.0-nightly (48cc71ee8 2026-03-31) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d4bb9bea82bb5..2f0cfb79a2e51 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-03-25" +channel = "nightly-2026-04-01" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From 29f956583deeb1f1f9e337ec492a961972014502 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 08:54:32 +1100 Subject: [PATCH 12/53] Move `rustc_middle::mir::mono` to `rustc_middle::mono` Because the things in this module aren't MIR and don't use anything from `rustc_middle::mir`. Also, modules that use `mono` often don't use anything else from `rustc_middle::mir`. --- src/driver/aot.rs | 2 +- src/driver/mod.rs | 2 +- src/linkage.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index b855e1fa4b780..c74e0b9b1a669 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -19,7 +19,7 @@ use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_hir::attrs::Linkage as RLinkage; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility}; +use rustc_middle::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility}; use rustc_session::Session; use rustc_session::config::{OutputFilenames, OutputType}; diff --git a/src/driver/mod.rs b/src/driver/mod.rs index 9f2b7b4b09f22..8d962aa1c7fba 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -6,7 +6,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::mono::{MonoItem, MonoItemData}; +use rustc_middle::mono::{MonoItem, MonoItemData}; use crate::prelude::*; diff --git a/src/linkage.rs b/src/linkage.rs index d76ab9d0109f0..e373268d76b76 100644 --- a/src/linkage.rs +++ b/src/linkage.rs @@ -1,5 +1,5 @@ use rustc_hir::attrs::Linkage as RLinkage; -use rustc_middle::mir::mono::{MonoItem, Visibility}; +use rustc_middle::mono::{MonoItem, Visibility}; use crate::prelude::*; From 70ee124a0b3f2230a3676c5b54c295b5220e9970 Mon Sep 17 00:00:00 2001 From: Finchie Date: Fri, 10 Apr 2026 12:31:22 +0800 Subject: [PATCH 13/53] Call rustc assembler with `-Zunstable-options` This allows custom JSON targets to compile, as the assembler was previously failing with an error that `-Zunstable-options` had not been set. --- src/global_asm.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/global_asm.rs b/src/global_asm.rs index b14988577845f..5765601763e44 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -235,6 +235,9 @@ pub(crate) fn compile_global_asm( .arg("-") .arg("-Abad_asm_style") .arg("-Zcodegen-backend=llvm") + // JSON targets currently require `-Zunstable-options` + // Tracking issue: https://github.com/rust-lang/rust/issues/151528 + .arg("-Zunstable-options") .stdin(Stdio::piped()) .spawn() .expect("Failed to spawn `as`."); From a52ff55f3888ea0bb15155b318a9ff99b3d436c5 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 11 Apr 2026 20:28:28 +0200 Subject: [PATCH 14/53] Merge commit '0557e3478104037c76c2e5be7ea21e56ebbaff6e' into sync-from-portable-simd-2026-04-11 --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- Cargo.lock | 418 ++++++++++++++++--------- Cargo.toml | 5 + beginners-guide.md | 2 +- crates/core_simd/Cargo.toml | 8 +- crates/core_simd/src/alias.rs | 10 + crates/core_simd/src/cast.rs | 3 + crates/core_simd/src/lib.rs | 6 +- crates/core_simd/src/masks.rs | 26 +- crates/core_simd/src/ops.rs | 2 +- crates/core_simd/src/ops/unary.rs | 2 + crates/core_simd/src/simd/cmp/eq.rs | 2 +- crates/core_simd/src/simd/cmp/ord.rs | 2 +- crates/core_simd/src/simd/num/float.rs | 2 +- crates/core_simd/src/simd/prelude.rs | 2 +- crates/core_simd/src/vector.rs | 18 +- crates/core_simd/src/vendor.rs | 3 + crates/core_simd/src/vendor/hexagon.rs | 40 +++ crates/core_simd/tests/f16_ops.rs | 10 + crates/core_simd/tests/masks.rs | 13 + crates/core_simd/tests/round.rs | 8 + crates/std_float/src/lib.rs | 17 + crates/std_float/tests/float.rs | 4 +- crates/test_helpers/Cargo.toml | 2 +- crates/test_helpers/src/biteq.rs | 2 +- crates/test_helpers/src/lib.rs | 5 +- crates/test_helpers/src/subnormals.rs | 2 +- rust-toolchain.toml | 2 +- triagebot.toml | 44 +++ 29 files changed, 469 insertions(+), 193 deletions(-) create mode 100644 crates/core_simd/src/vendor/hexagon.rs create mode 100644 crates/core_simd/tests/f16_ops.rs create mode 100644 triagebot.toml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 31422b7934501..5d354305e56de 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,7 +10,7 @@ For a given vector math operation on TxN, please add tests for interactions with - [ ] 0 -For a given vector math operation on TxN where T is a float, please add tests for test interactions with: +For a given vector math operation on TxN where T is a float, please add tests for interactions with: - [ ] a really large number, larger than the mantissa - [ ] a really small "subnormal" number - [ ] NaN diff --git a/Cargo.lock b/Cargo.lock index 5a5f0d8907ae3..c3b950bd5069c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -10,41 +21,43 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] -name = "byteorder" -version = "1.5.0" +name = "cast" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.33" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "core_simd" version = "0.1.0" dependencies = [ + "getrandom", "proptest", "std_float", "test_helpers", @@ -52,6 +65,12 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "float-cmp" version = "0.10.0" @@ -61,32 +80,99 @@ dependencies = [ "num-traits", ] +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] [[package]] -name = "log" -version = "0.4.27" +name = "libc" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "minicov" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +checksum = "4869b6a491569605d66d3952bcdf03df789e5b536e5f0cf7758a7f08a55ae24d" dependencies = [ "cc", "walkdir", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -94,13 +180,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "ppv-lite86" @@ -113,52 +212,58 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "0.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bitflags", - "byteorder", "num-traits", "rand", "rand_chacha", "rand_xorshift", + "regex-syntax", + "unarray", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.7.3" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", - "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.2.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -166,28 +271,28 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.5.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "rand_core", + "getrandom", ] [[package]] name = "rand_xorshift" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ "rand_core", ] +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + [[package]] name = "rustversion" version = "1.0.22" @@ -203,12 +308,61 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "std_float" version = "0.1.0" @@ -221,9 +375,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -238,11 +392,17 @@ dependencies = [ "proptest", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "walkdir" @@ -255,49 +415,42 @@ dependencies = [ ] [[package]] -name = "wasm-bindgen" -version = "0.2.100" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" +name = "wasm-bindgen" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -305,44 +458,53 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.50" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +checksum = "1138411301a026d6662dc44e7076a74dbaa76a369312275eea5dee4d7dc68c7c" dependencies = [ + "async-trait", + "cast", "js-sys", + "libm", "minicov", + "nu-ansi-term", + "num-traits", + "oorandom", + "serde", + "serde_json", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", + "wasm-bindgen-test-shared", ] [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.50" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +checksum = "186ddfe8383ba7ae7927bae3bb7343fd1f03ba2dbaf1474410f0d831131c269b" dependencies = [ "proc-macro2", "quote", @@ -350,113 +512,63 @@ dependencies = [ ] [[package]] -name = "web-sys" -version = "0.3.77" +name = "wasm-bindgen-test-shared" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] +checksum = "f032e076ceb8d36d5921c6cef5bf447f2ca2bbd5439ce1683d68d1c99cc2be16" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-link", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 21d4584a9f4d9..883140bae3f62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,8 @@ opt-level = 2 [profile.test.package.test_helpers] opt-level = 2 + +[workspace.dependencies.proptest] +version = "1.11" +default-features = false +features = ["alloc", "f16"] diff --git a/beginners-guide.md b/beginners-guide.md index 4250a18315a6e..c56873ea4b8d7 100644 --- a/beginners-guide.md +++ b/beginners-guide.md @@ -56,7 +56,7 @@ The list notes the bit widths available at each feature level, though the operat ### Selecting Additional Target Features -If you want to enable support for a target feature within your build, generally you should use a [target-feature](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-feature) setting within you `RUSTFLAGS` setting. +If you want to enable support for a target feature within your build, generally you should use a [target-feature](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-feature) setting within your `RUSTFLAGS` setting. If you know that you're targeting a specific CPU you can instead use the [target-cpu](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-cpu) flag and the compiler will enable the correct set of features for that CPU. diff --git a/crates/core_simd/Cargo.toml b/crates/core_simd/Cargo.toml index 537ce459c07cd..6e576084ecfba 100644 --- a/crates/core_simd/Cargo.toml +++ b/crates/core_simd/Cargo.toml @@ -18,9 +18,13 @@ wasm-bindgen = "0.2" wasm-bindgen-test = "0.3" [dev-dependencies.proptest] -version = "0.10" +workspace = true + +# Enable the `wasm_js` feature so that getrandom works on wasm32-unknown-unknown. +[dev-dependencies.getrandom] +version = "0.3.4" default-features = false -features = ["alloc"] +features = ["wasm_js"] [dev-dependencies.test_helpers] path = "../test_helpers" diff --git a/crates/core_simd/src/alias.rs b/crates/core_simd/src/alias.rs index 23f121c46197c..6dcfcb660c26a 100644 --- a/crates/core_simd/src/alias.rs +++ b/crates/core_simd/src/alias.rs @@ -153,6 +153,16 @@ alias! { usizex64 64 } + f16 = { + f16x1 1 + f16x2 2 + f16x4 4 + f16x8 8 + f16x16 16 + f16x32 32 + f16x64 64 + } + f32 = { f32x1 1 f32x2 2 diff --git a/crates/core_simd/src/cast.rs b/crates/core_simd/src/cast.rs index 1c3592f807578..69dc7ba50d58d 100644 --- a/crates/core_simd/src/cast.rs +++ b/crates/core_simd/src/cast.rs @@ -44,6 +44,9 @@ impl SimdCast for u64 {} unsafe impl Sealed for usize {} impl SimdCast for usize {} // Safety: primitive number types can be cast to other primitive number types +unsafe impl Sealed for f16 {} +impl SimdCast for f16 {} +// Safety: primitive number types can be cast to other primitive number types unsafe impl Sealed for f32 {} impl SimdCast for f32 {} // Safety: primitive number types can be cast to other primitive number types diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index fe26d99b9194c..413a886f6c5b8 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -1,17 +1,16 @@ #![no_std] #![feature( - const_eval_select, convert_float_to_int, + f16, core_intrinsics, decl_macro, - intra_doc_pointers, repr_simd, - simd_ffi, staged_api, prelude_import, ptr_metadata, rustc_attrs )] +#![cfg_attr(doc, feature(intra_doc_pointers))] #![cfg_attr( all( any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",), @@ -31,6 +30,7 @@ any(target_arch = "powerpc", target_arch = "powerpc64"), feature(stdarch_powerpc) )] +#![cfg_attr(target_arch = "hexagon", feature(stdarch_hexagon))] #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really #![deny( unsafe_op_in_unsafe_fn, diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index 3e2209556b66b..a5334afbe5f8b 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -371,22 +371,20 @@ where // * perform _unsigned_ reduce-min // * check if the result is -1 or an index - let index = Simd::from_array( - const { - let mut index = [0; N]; - let mut i = 0; - while i < N { - index[i] = i; - i += 1; - } - index - }, - ); + let index: Simd = const { + let mut index = [0; N]; + let mut i = 0; + while i < N { + index[i] = i; + i += 1; + } + // Safety: the input and output are integer vectors + unsafe { core::intrinsics::simd::simd_cast(Simd::from_array(index)) } + }; // Safety: the input and output are integer vectors - let index: Simd = unsafe { core::intrinsics::simd::simd_cast(index) }; - - let masked_index = self.select(index, Self::splat(true).to_simd()); + let masked_index: Simd = + unsafe { core::intrinsics::simd::simd_or((!self).to_simd(), index) }; // Safety: the input and output are integer vectors let masked_index: Simd = diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs index eb6601f734831..c0a06ed465129 100644 --- a/crates/core_simd/src/ops.rs +++ b/crates/core_simd/src/ops.rs @@ -245,7 +245,7 @@ for_base_ops! { // We don't need any special precautions here: // Floats always accept arithmetic ops, but may become NaN. for_base_ops! { - T = (f32, f64); + T = (f16, f32, f64); type Lhs = Simd; type Rhs = Simd; type Output = Self; diff --git a/crates/core_simd/src/ops/unary.rs b/crates/core_simd/src/ops/unary.rs index e1c06167f9790..af7aa8a823d99 100644 --- a/crates/core_simd/src/ops/unary.rs +++ b/crates/core_simd/src/ops/unary.rs @@ -19,6 +19,8 @@ macro_rules! neg { } neg! { + impl Neg for Simd + impl Neg for Simd impl Neg for Simd diff --git a/crates/core_simd/src/simd/cmp/eq.rs b/crates/core_simd/src/simd/cmp/eq.rs index d553d6c040c91..76836404cbc4e 100644 --- a/crates/core_simd/src/simd/cmp/eq.rs +++ b/crates/core_simd/src/simd/cmp/eq.rs @@ -42,7 +42,7 @@ macro_rules! impl_number { } } -impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } +impl_number! { f16, f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } macro_rules! impl_mask { { $($integer:ty),* } => { diff --git a/crates/core_simd/src/simd/cmp/ord.rs b/crates/core_simd/src/simd/cmp/ord.rs index 5672fbbf54caa..5a4e74c753b5a 100644 --- a/crates/core_simd/src/simd/cmp/ord.rs +++ b/crates/core_simd/src/simd/cmp/ord.rs @@ -144,7 +144,7 @@ macro_rules! impl_float { } } -impl_float! { f32, f64 } +impl_float! { f16, f32, f64 } macro_rules! impl_mask { { $($integer:ty),* } => { diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 175cbce4f58be..510f4c9eea393 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -444,4 +444,4 @@ macro_rules! impl_trait { } } -impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } +impl_trait! { f16 { bits: u16, mask: i16 }, f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } diff --git a/crates/core_simd/src/simd/prelude.rs b/crates/core_simd/src/simd/prelude.rs index e5d7a2aeb73df..6e93f16e10b1c 100644 --- a/crates/core_simd/src/simd/prelude.rs +++ b/crates/core_simd/src/simd/prelude.rs @@ -7,7 +7,7 @@ #[doc(no_inline)] pub use super::{ - Mask, Simd, + Mask, Select, Simd, ToBytes, cmp::{SimdOrd, SimdPartialEq, SimdPartialOrd}, num::{SimdFloat, SimdInt, SimdUint}, ptr::{SimdConstPtr, SimdMutPtr}, diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 5b3a689f3611b..fbef69f267aa5 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -363,7 +363,7 @@ where /// corresponding element in `enable` is `true`. /// /// When the element is disabled or out of bounds for the slice, that memory location - /// is not accessed and the corresponding value from `or` is passed through. + /// is not accessed and the default value for the element type is returned. /// /// # Examples /// ``` @@ -371,12 +371,11 @@ where /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; /// # use simd::{Simd, Mask}; - /// let vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - /// let enable = Mask::from_array([true, true, false, true]); - /// let or = Simd::from_array([-5, -4, -3, -2]); + /// let vec: Vec = vec![10, 11, 12]; + /// let enable = Mask::from_array([false, true, true, true]); /// - /// let result = Simd::load_select(&vec, enable, or); - /// assert_eq!(result, Simd::from_array([10, 11, -3, 13])); + /// let result = Simd::load_select_or_default(&vec, enable); + /// assert_eq!(result, Simd::from_array([0, 11, 12, 0])); /// ``` #[must_use] #[inline] @@ -1147,6 +1146,13 @@ unsafe impl SimdElement for isize { type Mask = isize; } +impl Sealed for f16 {} + +// Safety: f16 is a valid SIMD element type, and is supported by this API +unsafe impl SimdElement for f16 { + type Mask = i16; +} + impl Sealed for f32 {} // Safety: f32 is a valid SIMD element type, and is supported by this API diff --git a/crates/core_simd/src/vendor.rs b/crates/core_simd/src/vendor.rs index 57536e4fc77dc..6b3c640c2f7c5 100644 --- a/crates/core_simd/src/vendor.rs +++ b/crates/core_simd/src/vendor.rs @@ -32,3 +32,6 @@ mod powerpc; #[cfg(target_arch = "loongarch64")] mod loongarch64; + +#[cfg(target_arch = "hexagon")] +mod hexagon; diff --git a/crates/core_simd/src/vendor/hexagon.rs b/crates/core_simd/src/vendor/hexagon.rs new file mode 100644 index 0000000000000..2b8ea55fde659 --- /dev/null +++ b/crates/core_simd/src/vendor/hexagon.rs @@ -0,0 +1,40 @@ +//! Conversions to Hexagon HVX SIMD types. + +use crate::simd::*; + +// HVX 128-byte mode (1024-bit vectors) +// Enable with: -C target-feature=+hvx-length128b +#[cfg(target_feature = "hvx-length128b")] +mod hvx_128b { + use super::*; + use core::arch::hexagon::v128::HvxVector; + + // Full vectors (1024-bit) map to HvxVector + from_transmute! { unsafe u16x64 => HvxVector } + from_transmute! { unsafe i16x64 => HvxVector } + from_transmute! { unsafe u32x32 => HvxVector } + from_transmute! { unsafe i32x32 => HvxVector } + from_transmute! { unsafe u64x16 => HvxVector } + from_transmute! { unsafe i64x16 => HvxVector } + + // FIXME: u8x128/i8x128 don't exist in portable-simd (max lane count is 64) + // u8x64/i8x64 are only 512-bit (half of HvxVector in 128B mode) +} + +// HVX 64-byte mode (512-bit vectors) +// Default when hvx-length128b is not specified +#[cfg(not(target_feature = "hvx-length128b"))] +mod hvx_64b { + use super::*; + use core::arch::hexagon::v64::HvxVector; + + // Full vectors (512-bit) map to HvxVector + from_transmute! { unsafe u8x64 => HvxVector } + from_transmute! { unsafe i8x64 => HvxVector } + from_transmute! { unsafe u16x32 => HvxVector } + from_transmute! { unsafe i16x32 => HvxVector } + from_transmute! { unsafe u32x16 => HvxVector } + from_transmute! { unsafe i32x16 => HvxVector } + from_transmute! { unsafe u64x8 => HvxVector } + from_transmute! { unsafe i64x8 => HvxVector } +} diff --git a/crates/core_simd/tests/f16_ops.rs b/crates/core_simd/tests/f16_ops.rs new file mode 100644 index 0000000000000..f89bdf4738f8b --- /dev/null +++ b/crates/core_simd/tests/f16_ops.rs @@ -0,0 +1,10 @@ +#![feature(portable_simd)] +#![feature(f16)] + +#[macro_use] +mod ops_macros; + +// FIXME: some f16 operations cause rustc to hang on wasm simd +// https://github.com/llvm/llvm-project/issues/189251 +#[cfg(not(all(target_arch = "wasm32", target_feature = "simd128")))] +impl_float_tests! { f16, i16 } diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs index 53fb2367b6055..98a74be8e3955 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs @@ -133,6 +133,19 @@ macro_rules! test_mask_api { cast_impl::(); cast_impl::(); } + + #[test] + fn first_set() { + for bitmask in 0..=u8::MAX { + let mask = Mask::<$type, 8>::from_bitmask(bitmask as u64); + let expected = if bitmask == 0 { + None + } else { + Some(bitmask.trailing_zeros() as usize) + }; + assert_eq!(mask.first_set(), expected); + } + } } } } diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs index 4c1ac3c36f894..95b17f415822b 100644 --- a/crates/core_simd/tests/round.rs +++ b/crates/core_simd/tests/round.rs @@ -42,6 +42,14 @@ macro_rules! float_rounding_test { ) } + fn round_ties_even() { + test_helpers::test_unary_elementwise( + &Vector::::round_ties_even, + &Scalar::round_ties_even, + &|_| true, + ) + } + fn fract() { test_helpers::test_unary_elementwise_flush_subnormals( &Vector::::fract, diff --git a/crates/std_float/src/lib.rs b/crates/std_float/src/lib.rs index b269efc9b1d76..ff3525452231a 100644 --- a/crates/std_float/src/lib.rs +++ b/crates/std_float/src/lib.rs @@ -2,6 +2,7 @@ feature = "as_crate", feature(core_intrinsics), feature(portable_simd), + feature(f16), allow(internal_features) )] #[cfg(not(feature = "as_crate"))] @@ -156,14 +157,30 @@ pub trait StdFloat: Sealed + Sized { unsafe { intrinsics::simd_trunc(self) } } + /// Rounds each element to the nearest integer-valued float. + /// Ties are resolved by rounding to the number with an even least significant digit. + #[must_use = "method returns a new vector and does not mutate the original value"] + #[inline] + fn round_ties_even(self) -> Self { + unsafe { intrinsics::simd_round_ties_even(self) } + } + /// Returns the floating point's fractional value, with its integer part removed. #[must_use = "method returns a new vector and does not mutate the original value"] fn fract(self) -> Self; } +impl Sealed for Simd {} impl Sealed for Simd {} impl Sealed for Simd {} +impl StdFloat for Simd { + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } +} + impl StdFloat for Simd { #[inline] fn fract(self) -> Self { diff --git a/crates/std_float/tests/float.rs b/crates/std_float/tests/float.rs index c608ba49564e0..0fa5da3dca506 100644 --- a/crates/std_float/tests/float.rs +++ b/crates/std_float/tests/float.rs @@ -25,7 +25,7 @@ macro_rules! unary_approx_test { &core_simd::simd::Simd::<$scalar, LANES>::$func, &$scalar::$func, &|_| true, - 8, + 16, ) } )* @@ -71,7 +71,7 @@ macro_rules! impl_tests { mod $scalar { use std_float::StdFloat; - unary_test! { $scalar, sqrt, ceil, floor, round, trunc } + unary_test! { $scalar, sqrt, ceil, floor, round, trunc, round_ties_even } ternary_test! { $scalar, mul_add } // https://github.com/rust-lang/miri/issues/3555 diff --git a/crates/test_helpers/Cargo.toml b/crates/test_helpers/Cargo.toml index 408bb04c7aa40..da7ef7bd9945c 100644 --- a/crates/test_helpers/Cargo.toml +++ b/crates/test_helpers/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -proptest = { version = "0.10", default-features = false, features = ["alloc"] } +proptest = { workspace = true, features = ["alloc", "std"] } float-cmp = "0.10" diff --git a/crates/test_helpers/src/biteq.rs b/crates/test_helpers/src/biteq.rs index cbc20cda0d626..36761e37dea76 100644 --- a/crates/test_helpers/src/biteq.rs +++ b/crates/test_helpers/src/biteq.rs @@ -53,7 +53,7 @@ macro_rules! impl_float_biteq { }; } -impl_float_biteq! { f32, f64 } +impl_float_biteq! { f16, f32, f64 } impl BitEq for *const T { fn biteq(&self, other: &Self) -> bool { diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs index eb3d3f68bc2ea..82adb06d8a9d4 100644 --- a/crates/test_helpers/src/lib.rs +++ b/crates/test_helpers/src/lib.rs @@ -1,7 +1,7 @@ -#![feature(powerpc_target_feature)] +#![feature(f16)] #![cfg_attr( any(target_arch = "powerpc", target_arch = "powerpc64"), - feature(stdarch_powerpc) + feature(powerpc_target_feature, stdarch_powerpc) )] pub mod array; @@ -47,6 +47,7 @@ impl_num! { u16 } impl_num! { u32 } impl_num! { u64 } impl_num! { usize } +impl_num! { f16 } impl_num! { f32 } impl_num! { f64 } diff --git a/crates/test_helpers/src/subnormals.rs b/crates/test_helpers/src/subnormals.rs index b5f19ba47b819..44dfbb3d6c955 100644 --- a/crates/test_helpers/src/subnormals.rs +++ b/crates/test_helpers/src/subnormals.rs @@ -39,7 +39,7 @@ macro_rules! impl_else { } } -impl_float! { f32, f64 } +impl_float! { f16, f32, f64 } impl_else! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } /// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs. diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 639d07df73374..6a58e59fb93ef 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-01-26" +channel = "nightly-2026-03-18" components = ["rustfmt", "clippy", "miri", "rust-src"] diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 0000000000000..43048b5e4514c --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,44 @@ +## See for documentation +## of these features. + +# Allow users to use labels commands. +# Documentation at: https://forge.rust-lang.org/triagebot/labeling.html +[relabel] +allow-unauthenticated = [ + "A-*", + "C-*", + "E-*", + "F-*", + "I-*", + "ISA-*", + "O-*", +] + +# Allow users to assign 'r?` someone to an issue or PR. +# Documentation at: https://forge.rust-lang.org/triagebot/issue-assignment.html +[assign] +warn_non_default_branch = true + +# Warns when a PR contains merge commits +# Documentation at: https://forge.rust-lang.org/triagebot/no-merge.html +[no-merges] +exclude_titles = ["Sync from"] + +# Canonicalize issue numbers to avoid closing the wrong issue +# when commits are included in upstream sync, as well as warning links in commits. +# Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html +[issue-links] +check-commits = "uncanonicalized" + +# Enable issue transfers within the org +# Documentation at: https://forge.rust-lang.org/triagebot/transfer.html +[transfer] + +# Enable comments linking to triagebot range-diff when a PR is rebased +# onto a different base commit +# Documentation at: https://forge.rust-lang.org/triagebot/range-diff.html +[range-diff] + +# Add link to the review body to review changes since posting it. +# Documentation at: https://forge.rust-lang.org/triagebot/review-changes-since.html +[review-changes-since] From 81e7d7d99ed1f2890f8e2a32291a27d7088e094e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 12 Apr 2026 01:43:23 +0200 Subject: [PATCH 15/53] improve how `proptest` errors are displayed (#517) --- crates/test_helpers/src/lib.rs | 39 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs index 82adb06d8a9d4..ce3680ac2c306 100644 --- a/crates/test_helpers/src/lib.rs +++ b/crates/test_helpers/src/lib.rs @@ -122,12 +122,23 @@ pub fn make_runner() -> proptest::test_runner::TestRunner { proptest::test_runner::TestRunner::new(proptest::test_runner::Config::with_cases(4)) } +#[track_caller] +fn unwrap_test_error( + x: Result>, +) -> T { + // Using the `Display` instance of the error is much more readable. + match x { + Ok(v) => v, + Err(e) => panic!("{e}"), + } +} + /// Test a function that takes a single value. pub fn test_1( f: &dyn Fn(A) -> proptest::test_runner::TestCaseResult, ) { let mut runner = make_runner(); - runner.run(&A::default_strategy(), f).unwrap(); + unwrap_test_error(runner.run(&A::default_strategy(), f)) } /// Test a function that takes two values. @@ -135,11 +146,11 @@ pub fn test_2 proptest::test_runner::TestCaseResult, ) { let mut runner = make_runner(); - runner - .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| { + unwrap_test_error( + runner.run(&(A::default_strategy(), B::default_strategy()), |(a, b)| { f(a, b) - }) - .unwrap(); + }), + ) } /// Test a function that takes two values. @@ -151,16 +162,14 @@ pub fn test_3< f: &dyn Fn(A, B, C) -> proptest::test_runner::TestCaseResult, ) { let mut runner = make_runner(); - runner - .run( - &( - A::default_strategy(), - B::default_strategy(), - C::default_strategy(), - ), - |(a, b, c)| f(a, b, c), - ) - .unwrap(); + unwrap_test_error(runner.run( + &( + A::default_strategy(), + B::default_strategy(), + C::default_strategy(), + ), + |(a, b, c)| f(a, b, c), + )); } /// Test a unary vector function against a unary scalar function, applied elementwise. From d542d94602da86f579870b404cbcbbc0a460cffe Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 12 Apr 2026 21:52:34 +0200 Subject: [PATCH 16/53] Rustup to rustc 1.97.0-nightly (bf4fbfb7a 2026-04-11) --- rust-toolchain.toml | 2 +- src/driver/jit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 2f0cfb79a2e51..8b80ca1810d44 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-04-01" +channel = "nightly-2026-04-12" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 9bbc338a8e07c..3903e6ea3b1da 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -7,7 +7,7 @@ use std::os::raw::{c_char, c_int}; use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::mono::MonoItem; +use rustc_middle::mono::MonoItem; use rustc_session::Session; use rustc_session::config::OutputFilenames; use rustc_span::sym; From 86354453e582bbffb261ae9e6d6d7d7775cba9c7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 12 Apr 2026 21:52:50 +0200 Subject: [PATCH 17/53] Fix rustc test suite --- scripts/setup_rust_fork.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 2ca0c3cab910f..7ce54a45e2ce6 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -67,9 +67,9 @@ index bc68bfe396..00143ef3ed 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2230,7 +2230,7 @@ pub fn download_ci_rustc_commit<'a>( - return None; - } - + match freshness { + PathFreshness::LastModifiedUpstream { upstream } => upstream, + PathFreshness::HasLocalModifications { upstream, modifications } => { - if dwn_ctx.is_running_on_ci() { + if false && dwn_ctx.is_running_on_ci() { eprintln!("CI rustc commit matches with HEAD and we are in CI."); From a67de10494c49d76dce6aaaefc15da72cb58e053 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Apr 2026 21:03:50 +0200 Subject: [PATCH 18/53] preseve SIMD element type information and provide it to LLVM for better optimization --- src/abi/pass_mode.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 44b63aa95f83c..0283263cc6047 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -26,7 +26,9 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { (RegKind::Float, 4) => types::F32, (RegKind::Float, 8) => types::F64, (RegKind::Float, 16) => types::F128, - (RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(), + (RegKind::Vector { hint_vector_elem: _ }, size) => { + types::I8.by(u32::try_from(size).unwrap()).unwrap() + } _ => unreachable!("{:?}", reg), }; AbiParam::new(clif_ty) From 4fe5deaac71ed660be67229de6e5eb879b1df493 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 17 May 2025 14:35:25 +0000 Subject: [PATCH 19/53] Use `!null` pattern type in libcore --- example/mini_core.rs | 60 +++++++++++++++++++++++++++++--- example/mini_core_hello_world.rs | 23 ++++++++++-- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 218050982e6d3..ab9d2a743739f 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -8,6 +8,7 @@ rustc_attrs, rustc_private, transparent_unions, + pattern_types, auto_traits, freeze_impls )] @@ -15,6 +16,30 @@ #![no_core] #![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)] +#[lang = "pointee_trait"] +pub trait Pointee: PointeeSized { + #[lang = "metadata_type"] + // needed so that layout_of will return `TooGeneric` instead of `Unknown` + // when asked for the layout of `*const T`. Which is important for making + // transmutes between raw pointers (and especially pattern types of raw pointers) + // work. + type Metadata: Copy + Sync + Unpin + Freeze; +} + +#[lang = "dyn_metadata"] +pub struct DynMetadata { + _vtable_ptr: NonNull, + _phantom: PhantomData, +} + +unsafe extern "C" { + /// Opaque type for accessing vtables. + /// + /// Private implementation detail of `DynMetadata::size_of` etc. + /// There is conceptually not actually any Abstract Machine memory behind this pointer. + type VTable; +} + #[lang = "pointee_sized"] pub trait PointeeSized {} @@ -105,7 +130,7 @@ unsafe impl<'a, T: PointeeSized> Sync for &'a T {} unsafe impl Sync for [T; N] {} #[lang = "freeze"] -unsafe auto trait Freeze {} +pub unsafe auto trait Freeze {} unsafe impl Freeze for PhantomData {} unsafe impl Freeze for *const T {} @@ -570,10 +595,24 @@ pub trait Deref { fn deref(&self) -> &Self::Target; } +#[rustc_builtin_macro(pattern_type)] +#[macro_export] +macro_rules! pattern_type { + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} + +impl CoerceUnsized for pattern_type!(*const T is !null) where + T: Unsize +{ +} + +impl, U> DispatchFromDyn for pattern_type!(T is !null) {} + #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] -pub struct NonNull(pub *const T); +pub struct NonNull(pub pattern_type!(*const T is !null)); impl CoerceUnsized> for NonNull where T: Unsize {} impl DispatchFromDyn> for NonNull where T: Unsize {} @@ -600,7 +639,16 @@ impl Box { let size = size_of::(); let ptr = libc::malloc(size); intrinsics::copy(&val as *const T as *const u8, ptr, size); - Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global) + Box( + Unique { + pointer: NonNull(intrinsics::transmute::< + *mut u8, + pattern_type!(*const T is !null), + >(ptr)), + _marker: PhantomData, + }, + Global, + ) } } } @@ -609,7 +657,9 @@ impl Drop for Box { fn drop(&mut self) { // inner value is dropped by compiler unsafe { - libc::free(self.0.pointer.0 as *mut u8); + libc::free(intrinsics::transmute::( + self.0.pointer.0, + ) as *mut u8); } } } diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 6734d19fbb48b..5e986201b385c 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -1,4 +1,13 @@ -#![feature(no_core, lang_items, never_type, extern_types, thread_local, repr_simd, rustc_private)] +#![feature( + no_core, + lang_items, + never_type, + extern_types, + thread_local, + repr_simd, + pattern_types, + rustc_private +)] #![cfg_attr(not(any(jit, target_vendor = "apple", windows)), feature(linkage))] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] @@ -153,7 +162,10 @@ extern "C" fn bool_struct_in_11(_arg0: bool_11) {} #[allow(unreachable_code)] // FIXME false positive fn main() { - take_unique(Unique { pointer: unsafe { NonNull(1 as *mut ()) }, _marker: PhantomData }); + take_unique(Unique { + pointer: unsafe { NonNull(intrinsics::transmute(1 as *mut ())) }, + _marker: PhantomData, + }); take_f32(0.1); call_return_u128_pair(); @@ -219,7 +231,12 @@ fn main() { let noisy_unsized_drop = const { intrinsics::needs_drop::() }; assert!(noisy_unsized_drop); - Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique; + Unique { + pointer: NonNull(intrinsics::transmute::<_, pattern_type!(*const &str is !null)>( + 1 as *mut &str, + )), + _marker: PhantomData, + } as Unique; struct MyDst(T); From 438d886b84b90dd905c54c6bb94e4c56faf77310 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Tue, 14 Apr 2026 11:43:00 +0300 Subject: [PATCH 20/53] Lock stable_crate_ids once in create_crate_num --- compiler/rustc_middle/src/ty/context.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b908a6c6e8439..d439645d3542c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1411,12 +1411,12 @@ impl<'tcx> TyCtxt<'tcx> { self, stable_crate_id: StableCrateId, ) -> Result, CrateNum> { - if let Some(&existing) = self.untracked().stable_crate_ids.read().get(&stable_crate_id) { + let mut lock = self.untracked().stable_crate_ids.write(); + if let Some(&existing) = lock.get(&stable_crate_id) { return Err(existing); } - - let num = CrateNum::new(self.untracked().stable_crate_ids.read().len()); - self.untracked().stable_crate_ids.write().insert(stable_crate_id, num); + let num = CrateNum::new(lock.len()); + lock.insert(stable_crate_id, num); Ok(TyCtxtFeed { key: num, tcx: self }) } From c418fe72569012d93e511e90cc8305db3a74f07d Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 14 Apr 2026 11:35:26 -0700 Subject: [PATCH 21/53] `CValue::zst()` - add missing "ZST" in docs --- src/value_and_place.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 5b76a4cb97793..9dc5012a602dc 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -98,7 +98,7 @@ impl<'tcx> CValue<'tcx> { /// Create an instance of a ZST /// - /// The is represented by a dangling pointer of suitable alignment. + /// The ZST is represented by a dangling pointer of suitable alignment. pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> { assert!(layout.is_zst()); CValue::by_ref(crate::Pointer::dangling(layout.align.abi), layout) From c08e62ab7734ce15341c843ca7513c75d72770d5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 15 Apr 2026 16:32:55 +0200 Subject: [PATCH 22/53] Rustup to rustc 1.97.0-nightly (a5c825cd8 2026-04-14) --- rust-toolchain.toml | 2 +- src/intrinsics/simd.rs | 139 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 127 insertions(+), 14 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8b80ca1810d44..7ec491b1b5dd9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-04-12" +channel = "nightly-2026-04-15" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index cc2311a67b5d5..bb93926fd07b5 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -91,23 +91,26 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual, x_lane, y_lane) } + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift + // `fcmp` once `f16`/`f128` backend lowerings have been added to + // Cranelift. (ty::Float(_), sym::simd_eq) => { - fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane) + codegen_f16_f128::fcmp(fx, FloatCC::Equal, x_lane, y_lane) } (ty::Float(_), sym::simd_ne) => { - fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane) + codegen_f16_f128::fcmp(fx, FloatCC::NotEqual, x_lane, y_lane) } (ty::Float(_), sym::simd_lt) => { - fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane) + codegen_f16_f128::fcmp(fx, FloatCC::LessThan, x_lane, y_lane) } (ty::Float(_), sym::simd_le) => { - fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, x_lane, y_lane) + codegen_f16_f128::fcmp(fx, FloatCC::LessThanOrEqual, x_lane, y_lane) } (ty::Float(_), sym::simd_gt) => { - fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane) + codegen_f16_f128::fcmp(fx, FloatCC::GreaterThan, x_lane, y_lane) } (ty::Float(_), sym::simd_ge) => { - fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, x_lane, y_lane) + codegen_f16_f128::fcmp(fx, FloatCC::GreaterThanOrEqual, x_lane, y_lane) } _ => unreachable!(), @@ -391,6 +394,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( intrinsic, ) { (ty::Int(_), sym::simd_neg) => fx.bcx.ins().ineg(lane), + (ty::Float(FloatTy::F16), sym::simd_neg) => codegen_f16_f128::neg_f16(fx, lane), (ty::Float(_), sym::simd_neg) => fx.bcx.ins().fneg(lane), (ty::Uint(ty::UintTy::U8) | ty::Int(ty::IntTy::I8), sym::simd_bswap) => lane, @@ -418,7 +422,18 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // FIXME use vector instructions when possible simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| { - match (lane_ty.kind(), intrinsic) { + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (x_lane, y_lane) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + ( + codegen_f16_f128::f16_to_f32(fx, x_lane), + codegen_f16_f128::f16_to_f32(fx, y_lane), + ) + } else { + (x_lane, y_lane) + }; + + let res = match (lane_ty.kind(), intrinsic) { (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), @@ -435,6 +450,16 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane), (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane), (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane), + (ty::Float(FloatTy::F16), sym::simd_rem) => fx.lib_call( + "fmodf", + vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], + vec![AbiParam::new(types::F32)], + // FIXME(bytecodealliance/wasmtime#8312): Already converted + // by the FIXME above. + // fx.bcx.ins().fpromote(types::F32, lhs), + // fx.bcx.ins().fpromote(types::F32, rhs), + &[x_lane, y_lane], + )[0], (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call( "fmodf", vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], @@ -461,6 +486,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), _ => unreachable!(), + }; + + if *lane_ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res } }); } @@ -486,7 +520,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let b_lane = b.value_lane(fx, lane).load_scalar(fx); let c_lane = c.value_lane(fx, lane).load_scalar(fx); - let res_lane = fx.bcx.ins().fma(a_lane, b_lane, c_lane); + let res_lane = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + codegen_f16_f128::fma_f16(fx, a_lane, b_lane, c_lane) + } else { + fx.bcx.ins().fma(a_lane, b_lane, c_lane) + }; let res_lane = CValue::by_val(res_lane, res_lane_layout); ret.place_lane(fx, lane).write_cvalue(fx, res_lane); @@ -584,13 +622,28 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ty::Float(_) => {} _ => unreachable!("{:?}", lane_ty), } - match intrinsic { + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let lane = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + codegen_f16_f128::f16_to_f32(fx, lane) + } else { + lane + }; + let res = match intrinsic { sym::simd_fabs => fx.bcx.ins().fabs(lane), sym::simd_fsqrt => fx.bcx.ins().sqrt(lane), sym::simd_ceil => fx.bcx.ins().ceil(lane), sym::simd_floor => fx.bcx.ins().floor(lane), sym::simd_trunc => fx.bcx.ins().trunc(lane), _ => unreachable!(), + }; + if *lane_ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res } }); } @@ -607,7 +660,22 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - fx.bcx.ins().fadd(a, b) + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) + } else { + (a, b) + }; + let res = fx.bcx.ins().fadd(a, b); + if *lane_ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res + } } else { fx.bcx.ins().iadd(a, b) } @@ -625,7 +693,22 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, None, ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - fx.bcx.ins().fadd(a, b) + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) + } else { + (a, b) + }; + let res = fx.bcx.ins().fadd(a, b); + if *lane_ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res + } } else { fx.bcx.ins().iadd(a, b) } @@ -644,7 +727,22 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - fx.bcx.ins().fmul(a, b) + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) + } else { + (a, b) + }; + let res = fx.bcx.ins().fmul(a, b); + if *lane_ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res + } } else { fx.bcx.ins().imul(a, b) } @@ -662,7 +760,22 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, None, ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - fx.bcx.ins().fmul(a, b) + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { + (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) + } else { + (a, b) + }; + let res = fx.bcx.ins().fmul(a, b); + if *lane_ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res + } } else { fx.bcx.ins().imul(a, b) } From ff5d860e90ef7743ca914475f1a771f8e3960073 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 15 Apr 2026 16:50:08 +0200 Subject: [PATCH 23/53] Introduce helper functions for f16<->f32 casts when necessary --- src/codegen_f16_f128.rs | 34 ++++++ src/intrinsics/mod.rs | 18 ++-- src/intrinsics/simd.rs | 229 +++++++++++++--------------------------- src/num.rs | 23 ++-- 4 files changed, 120 insertions(+), 184 deletions(-) diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs index d8977657e305d..e63e4bebf78a2 100644 --- a/src/codegen_f16_f128.rs +++ b/src/codegen_f16_f128.rs @@ -51,6 +51,40 @@ fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } } +// FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have +// been added to Cranelift. +pub(crate) fn maybe_with_f16_to_f32( + fx: &mut FunctionCx<'_, '_, '_>, + val: Value, + f: impl FnOnce(&mut FunctionCx<'_, '_, '_>, Value) -> Value, +) -> Value { + if fx.bcx.func.dfg.value_type(val) == types::F16 { + let val = f16_to_f32(fx, val); + let res = f(fx, val); + f32_to_f16(fx, res) + } else { + f(fx, val) + } +} + +// FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have +// been added to Cranelift. +pub(crate) fn maybe_with_f16_to_f32_pair( + fx: &mut FunctionCx<'_, '_, '_>, + a: Value, + b: Value, + f: impl FnOnce(&mut FunctionCx<'_, '_, '_>, Value, Value) -> Value, +) -> Value { + if fx.bcx.func.dfg.value_type(a) == types::F16 { + let a = f16_to_f32(fx, a); + let b = f16_to_f32(fx, b); + let res = f(fx, a, b); + f32_to_f16(fx, res) + } else { + f(fx, a, b) + } +} + pub(crate) fn fcmp(fx: &mut FunctionCx<'_, '_, '_>, cc: FloatCC, lhs: Value, rhs: Value) -> Value { let ty = fx.bcx.func.dfg.value_type(lhs); match ty { diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 780550fc4cc74..95c47715d19df 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -1197,12 +1197,9 @@ fn codegen_regular_intrinsic_call<'tcx>( let a = a.load_scalar(fx); let b = b.load_scalar(fx); - // FIXME(bytecodealliance/wasmtime#8312): Use `fmin` directly once - // Cranelift backend lowerings are implemented. - let a = codegen_f16_f128::f16_to_f32(fx, a); - let b = codegen_f16_f128::f16_to_f32(fx, b); - let val = fx.bcx.ins().fmin(a, b); - let val = codegen_f16_f128::f32_to_f16(fx, val); + let val = codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { + fx.bcx.ins().fmin(a, b) + }); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); ret.write_cvalue(fx, val); } @@ -1240,12 +1237,9 @@ fn codegen_regular_intrinsic_call<'tcx>( let a = a.load_scalar(fx); let b = b.load_scalar(fx); - // FIXME(bytecodealliance/wasmtime#8312): Use `fmax` directly once - // Cranelift backend lowerings are implemented. - let a = codegen_f16_f128::f16_to_f32(fx, a); - let b = codegen_f16_f128::f16_to_f32(fx, b); - let val = fx.bcx.ins().fmax(a, b); - let val = codegen_f16_f128::f32_to_f16(fx, val); + let val = codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { + fx.bcx.ins().fmax(a, b) + }); let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); ret.write_cvalue(fx, val); } diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index bb93926fd07b5..b8e1886b2d3c1 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -422,80 +422,65 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // FIXME use vector instructions when possible simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| { - // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have - // been added to Cranelift. - let (x_lane, y_lane) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { - ( - codegen_f16_f128::f16_to_f32(fx, x_lane), - codegen_f16_f128::f16_to_f32(fx, y_lane), - ) - } else { - (x_lane, y_lane) - }; - - let res = match (lane_ty.kind(), intrinsic) { - (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), - (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), - (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), - (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane), - (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane), - - (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), - (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), - (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), - (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane), - (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane), - - (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane), - (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane), - (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane), - (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane), - (ty::Float(FloatTy::F16), sym::simd_rem) => fx.lib_call( - "fmodf", - vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], - vec![AbiParam::new(types::F32)], - // FIXME(bytecodealliance/wasmtime#8312): Already converted - // by the FIXME above. - // fx.bcx.ins().fpromote(types::F32, lhs), - // fx.bcx.ins().fpromote(types::F32, rhs), - &[x_lane, y_lane], - )[0], - (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call( - "fmodf", - vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], - vec![AbiParam::new(types::F32)], - &[x_lane, y_lane], - )[0], - (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call( - "fmod", - vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], - vec![AbiParam::new(types::F64)], - &[x_lane, y_lane], - )[0], - - (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), - (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane), - (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), - (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), - (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), - - (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), - (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane), - (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), - (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), - (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), - - _ => unreachable!(), - }; - - if *lane_ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, res) - } else { - res - } + codegen_f16_f128::maybe_with_f16_to_f32_pair( + fx, + x_lane, + y_lane, + |fx, x_lane, y_lane| match (lane_ty.kind(), intrinsic) { + (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), + (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), + (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), + (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane), + (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane), + + (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), + (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), + (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), + (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane), + (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane), + + (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane), + (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane), + (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane), + (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane), + (ty::Float(FloatTy::F16), sym::simd_rem) => fx.lib_call( + "fmodf", + vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], + vec![AbiParam::new(types::F32)], + // FIXME(bytecodealliance/wasmtime#8312): Already converted + // by the FIXME above. + // fx.bcx.ins().fpromote(types::F32, lhs), + // fx.bcx.ins().fpromote(types::F32, rhs), + &[x_lane, y_lane], + )[0], + (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call( + "fmodf", + vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], + vec![AbiParam::new(types::F32)], + &[x_lane, y_lane], + )[0], + (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call( + "fmod", + vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], + vec![AbiParam::new(types::F64)], + &[x_lane, y_lane], + )[0], + + (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), + (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane), + (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), + (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), + (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), + + (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), + (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane), + (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), + (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), + (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), + + _ => unreachable!(), + }, + ) }); } @@ -622,29 +607,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ty::Float(_) => {} _ => unreachable!("{:?}", lane_ty), } - // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have - // been added to Cranelift. - let lane = if *lane_ty.kind() == ty::Float(FloatTy::F16) { - codegen_f16_f128::f16_to_f32(fx, lane) - } else { - lane - }; - let res = match intrinsic { + + codegen_f16_f128::maybe_with_f16_to_f32(fx, lane, |fx, lane| match intrinsic { sym::simd_fabs => fx.bcx.ins().fabs(lane), sym::simd_fsqrt => fx.bcx.ins().sqrt(lane), sym::simd_ceil => fx.bcx.ins().ceil(lane), sym::simd_floor => fx.bcx.ins().floor(lane), sym::simd_trunc => fx.bcx.ins().trunc(lane), _ => unreachable!(), - }; - if *lane_ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, res) - } else { - res - } + }) }); } @@ -660,22 +631,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have - // been added to Cranelift. - let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { - (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) - } else { - (a, b) - }; - let res = fx.bcx.ins().fadd(a, b); - if *lane_ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, res) - } else { - res - } + codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { + fx.bcx.ins().fadd(a, b) + }) } else { fx.bcx.ins().iadd(a, b) } @@ -693,22 +651,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, None, ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have - // been added to Cranelift. - let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { - (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) - } else { - (a, b) - }; - let res = fx.bcx.ins().fadd(a, b); - if *lane_ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, res) - } else { - res - } + codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { + fx.bcx.ins().fadd(a, b) + }) } else { fx.bcx.ins().iadd(a, b) } @@ -727,22 +672,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have - // been added to Cranelift. - let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { - (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) - } else { - (a, b) - }; - let res = fx.bcx.ins().fmul(a, b); - if *lane_ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, res) - } else { - res - } + codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { + fx.bcx.ins().fmul(a, b) + }) } else { fx.bcx.ins().imul(a, b) } @@ -760,22 +692,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_reduce(fx, v, None, ret, &|fx, lane_ty, a, b| { if lane_ty.is_floating_point() { - // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have - // been added to Cranelift. - let (a, b) = if *lane_ty.kind() == ty::Float(FloatTy::F16) { - (codegen_f16_f128::f16_to_f32(fx, a), codegen_f16_f128::f16_to_f32(fx, b)) - } else { - (a, b) - }; - let res = fx.bcx.ins().fmul(a, b); - if *lane_ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, res) - } else { - res - } + codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { + fx.bcx.ins().fmul(a, b) + }) } else { fx.bcx.ins().imul(a, b) } diff --git a/src/num.rs b/src/num.rs index e583f3f2f754a..e533c0b631b01 100644 --- a/src/num.rs +++ b/src/num.rs @@ -358,7 +358,6 @@ pub(crate) fn codegen_float_binop<'tcx>( } else { (lhs, rhs) }; - let b = fx.bcx.ins(); let res = match bin_op { // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings // have been added to Cranelift. @@ -367,10 +366,10 @@ pub(crate) fn codegen_float_binop<'tcx>( { codegen_f16_f128::codegen_f128_binop(fx, bin_op, lhs, rhs) } - BinOp::Add => b.fadd(lhs, rhs), - BinOp::Sub => b.fsub(lhs, rhs), - BinOp::Mul => b.fmul(lhs, rhs), - BinOp::Div => b.fdiv(lhs, rhs), + BinOp::Add => fx.bcx.ins().fadd(lhs, rhs), + BinOp::Sub => fx.bcx.ins().fsub(lhs, rhs), + BinOp::Mul => fx.bcx.ins().fmul(lhs, rhs), + BinOp::Div => fx.bcx.ins().fdiv(lhs, rhs), BinOp::Rem => { let (name, ty, lhs, rhs) = match in_lhs.layout().ty.kind() { ty::Float(FloatTy::F16) => ( @@ -389,22 +388,12 @@ pub(crate) fn codegen_float_binop<'tcx>( _ => bug!(), }; - let ret_val = fx.lib_call( + fx.lib_call( name, vec![AbiParam::new(ty), AbiParam::new(ty)], vec![AbiParam::new(ty)], &[lhs, rhs], - )[0]; - - let ret_val = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { - // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift - // operation once Cranelift backend lowerings have been - // implemented. - codegen_f16_f128::f32_to_f16(fx, ret_val) - } else { - ret_val - }; - return CValue::by_val(ret_val, in_lhs.layout()); + )[0] } BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { let fltcc = match bin_op { From 657259f645c88325eb94fe8b4000b4aeacb6a155 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 8 Apr 2026 15:01:26 +1000 Subject: [PATCH 24/53] Refactor FnDecl and FnSig flags into packed structs --- src/value_and_place.rs | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 9dc5012a602dc..67adbaf028eb9 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -870,20 +870,10 @@ pub(crate) fn assert_assignable<'tcx>( let from_sig = fx .tcx .normalize_erasing_late_bound_regions(fx.typing_env(), from_ty.fn_sig(fx.tcx)); - let FnSig { - inputs_and_output: types_from, - c_variadic: c_variadic_from, - safety: unsafety_from, - abi: abi_from, - } = from_sig; + let FnSig { inputs_and_output: types_from, fn_sig_kind: fn_sig_kind_from } = from_sig; let to_sig = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to_ty.fn_sig(fx.tcx)); - let FnSig { - inputs_and_output: types_to, - c_variadic: c_variadic_to, - safety: unsafety_to, - abi: abi_to, - } = to_sig; + let FnSig { inputs_and_output: types_to, fn_sig_kind: fn_sig_kind_to } = to_sig; let mut types_from = types_from.iter(); let mut types_to = types_to.iter(); loop { @@ -894,17 +884,7 @@ pub(crate) fn assert_assignable<'tcx>( } } assert_eq!( - c_variadic_from, c_variadic_to, - "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", - from_sig, to_sig, fx, - ); - assert_eq!( - unsafety_from, unsafety_to, - "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", - from_sig, to_sig, fx, - ); - assert_eq!( - abi_from, abi_to, + fn_sig_kind_from, fn_sig_kind_to, "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", from_sig, to_sig, fx, ); From 644a946d85d88ee79ea571b74141cfbe0e3fe10f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:03:16 +0200 Subject: [PATCH 25/53] Disable f16 portable-simd tests on x86_64-pc-windows-gnu It is currently broken on x86_64-pc-windows-gnu --- ...d-Disable-f16-usage-in-portable-simd.patch | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch diff --git a/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch b/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch new file mode 100644 index 0000000000000..029e493227cd1 --- /dev/null +++ b/patches/0001-portable-simd-Disable-f16-usage-in-portable-simd.patch @@ -0,0 +1,266 @@ +From 2aa88b261ffb51d3f18a4b9d3b79232d7445e5f3 Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Thu, 16 Apr 2026 17:29:02 +0200 +Subject: [PATCH] Disable f16 usage in portable-simd + +It is currently broken on x86_64-pc-windows-gnu +--- + Cargo.toml | 8 ++------ + crates/core_simd/src/alias.rs | 10 ---------- + crates/core_simd/src/cast.rs | 3 --- + crates/core_simd/src/lib.rs | 1 - + crates/core_simd/src/ops.rs | 2 +- + crates/core_simd/src/ops/unary.rs | 2 -- + crates/core_simd/src/simd/cmp/eq.rs | 2 +- + crates/core_simd/src/simd/cmp/ord.rs | 2 +- + crates/core_simd/src/simd/num/float.rs | 2 +- + crates/core_simd/src/vector.rs | 7 ------- + crates/core_simd/tests/f16_ops.rs | 10 ---------- + crates/std_float/src/lib.rs | 9 --------- + crates/test_helpers/src/biteq.rs | 2 +- + crates/test_helpers/src/lib.rs | 2 -- + crates/test_helpers/src/subnormals.rs | 2 +- + 15 files changed, 8 insertions(+), 56 deletions(-) + delete mode 100644 crates/core_simd/tests/f16_ops.rs + +diff --git a/Cargo.toml b/Cargo.toml +index 883140b..45296b4 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -1,10 +1,6 @@ + [workspace] + resolver = "1" +-members = [ +- "crates/core_simd", +- "crates/std_float", +- "crates/test_helpers", +-] ++members = ["crates/core_simd", "crates/std_float", "crates/test_helpers"] + + [profile.test.package."*"] + opt-level = 2 +@@ -15,4 +11,4 @@ opt-level = 2 + [workspace.dependencies.proptest] + version = "1.11" + default-features = false +-features = ["alloc", "f16"] ++features = ["alloc"] +diff --git a/crates/core_simd/src/alias.rs b/crates/core_simd/src/alias.rs +index 6dcfcb6..23f121c 100644 +--- a/crates/core_simd/src/alias.rs ++++ b/crates/core_simd/src/alias.rs +@@ -153,16 +153,6 @@ alias! { + usizex64 64 + } + +- f16 = { +- f16x1 1 +- f16x2 2 +- f16x4 4 +- f16x8 8 +- f16x16 16 +- f16x32 32 +- f16x64 64 +- } +- + f32 = { + f32x1 1 + f32x2 2 +diff --git a/crates/core_simd/src/cast.rs b/crates/core_simd/src/cast.rs +index 69dc7ba..1c3592f 100644 +--- a/crates/core_simd/src/cast.rs ++++ b/crates/core_simd/src/cast.rs +@@ -44,9 +44,6 @@ impl SimdCast for u64 {} + unsafe impl Sealed for usize {} + impl SimdCast for usize {} + // Safety: primitive number types can be cast to other primitive number types +-unsafe impl Sealed for f16 {} +-impl SimdCast for f16 {} +-// Safety: primitive number types can be cast to other primitive number types + unsafe impl Sealed for f32 {} + impl SimdCast for f32 {} + // Safety: primitive number types can be cast to other primitive number types +diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs +index 413a886..115be44 100644 +--- a/crates/core_simd/src/lib.rs ++++ b/crates/core_simd/src/lib.rs +@@ -1,7 +1,6 @@ + #![no_std] + #![feature( + convert_float_to_int, +- f16, + core_intrinsics, + decl_macro, + repr_simd, +diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs +index c0a06ed..eb6601f 100644 +--- a/crates/core_simd/src/ops.rs ++++ b/crates/core_simd/src/ops.rs +@@ -245,7 +245,7 @@ for_base_ops! { + // We don't need any special precautions here: + // Floats always accept arithmetic ops, but may become NaN. + for_base_ops! { +- T = (f16, f32, f64); ++ T = (f32, f64); + type Lhs = Simd; + type Rhs = Simd; + type Output = Self; +diff --git a/crates/core_simd/src/ops/unary.rs b/crates/core_simd/src/ops/unary.rs +index af7aa8a..e1c0616 100644 +--- a/crates/core_simd/src/ops/unary.rs ++++ b/crates/core_simd/src/ops/unary.rs +@@ -19,8 +19,6 @@ macro_rules! neg { + } + + neg! { +- impl Neg for Simd +- + impl Neg for Simd + + impl Neg for Simd +diff --git a/crates/core_simd/src/simd/cmp/eq.rs b/crates/core_simd/src/simd/cmp/eq.rs +index 7683640..d553d6c 100644 +--- a/crates/core_simd/src/simd/cmp/eq.rs ++++ b/crates/core_simd/src/simd/cmp/eq.rs +@@ -42,7 +42,7 @@ macro_rules! impl_number { + } + } + +-impl_number! { f16, f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } ++impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } + + macro_rules! impl_mask { + { $($integer:ty),* } => { +diff --git a/crates/core_simd/src/simd/cmp/ord.rs b/crates/core_simd/src/simd/cmp/ord.rs +index 5a4e74c..5672fbb 100644 +--- a/crates/core_simd/src/simd/cmp/ord.rs ++++ b/crates/core_simd/src/simd/cmp/ord.rs +@@ -144,7 +144,7 @@ macro_rules! impl_float { + } + } + +-impl_float! { f16, f32, f64 } ++impl_float! { f32, f64 } + + macro_rules! impl_mask { + { $($integer:ty),* } => { +diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs +index 510f4c9..175cbce 100644 +--- a/crates/core_simd/src/simd/num/float.rs ++++ b/crates/core_simd/src/simd/num/float.rs +@@ -444,4 +444,4 @@ macro_rules! impl_trait { + } + } + +-impl_trait! { f16 { bits: u16, mask: i16 }, f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } ++impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } } +diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs +index fbef69f..c8e0b8c 100644 +--- a/crates/core_simd/src/vector.rs ++++ b/crates/core_simd/src/vector.rs +@@ -1146,13 +1146,6 @@ unsafe impl SimdElement for isize { + type Mask = isize; + } + +-impl Sealed for f16 {} +- +-// Safety: f16 is a valid SIMD element type, and is supported by this API +-unsafe impl SimdElement for f16 { +- type Mask = i16; +-} +- + impl Sealed for f32 {} + + // Safety: f32 is a valid SIMD element type, and is supported by this API +diff --git a/crates/core_simd/tests/f16_ops.rs b/crates/core_simd/tests/f16_ops.rs +deleted file mode 100644 +index f89bdf4..0000000 +--- a/crates/core_simd/tests/f16_ops.rs ++++ /dev/null +@@ -1,10 +0,0 @@ +-#![feature(portable_simd)] +-#![feature(f16)] +- +-#[macro_use] +-mod ops_macros; +- +-// FIXME: some f16 operations cause rustc to hang on wasm simd +-// https://github.com/llvm/llvm-project/issues/189251 +-#[cfg(not(all(target_arch = "wasm32", target_feature = "simd128")))] +-impl_float_tests! { f16, i16 } +diff --git a/crates/std_float/src/lib.rs b/crates/std_float/src/lib.rs +index ff35254..acc1bfc 100644 +--- a/crates/std_float/src/lib.rs ++++ b/crates/std_float/src/lib.rs +@@ -2,7 +2,6 @@ + feature = "as_crate", + feature(core_intrinsics), + feature(portable_simd), +- feature(f16), + allow(internal_features) + )] + #[cfg(not(feature = "as_crate"))] +@@ -170,17 +169,9 @@ pub trait StdFloat: Sealed + Sized { + fn fract(self) -> Self; + } + +-impl Sealed for Simd {} + impl Sealed for Simd {} + impl Sealed for Simd {} + +-impl StdFloat for Simd { +- #[inline] +- fn fract(self) -> Self { +- self - self.trunc() +- } +-} +- + impl StdFloat for Simd { + #[inline] + fn fract(self) -> Self { +diff --git a/crates/test_helpers/src/biteq.rs b/crates/test_helpers/src/biteq.rs +index 36761e3..cbc20cd 100644 +--- a/crates/test_helpers/src/biteq.rs ++++ b/crates/test_helpers/src/biteq.rs +@@ -53,7 +53,7 @@ macro_rules! impl_float_biteq { + }; + } + +-impl_float_biteq! { f16, f32, f64 } ++impl_float_biteq! { f32, f64 } + + impl BitEq for *const T { + fn biteq(&self, other: &Self) -> bool { +diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs +index 82adb06..4b03674 100644 +--- a/crates/test_helpers/src/lib.rs ++++ b/crates/test_helpers/src/lib.rs +@@ -1,4 +1,3 @@ +-#![feature(f16)] + #![cfg_attr( + any(target_arch = "powerpc", target_arch = "powerpc64"), + feature(powerpc_target_feature, stdarch_powerpc) +@@ -47,7 +46,6 @@ impl_num! { u16 } + impl_num! { u32 } + impl_num! { u64 } + impl_num! { usize } +-impl_num! { f16 } + impl_num! { f32 } + impl_num! { f64 } + +diff --git a/crates/test_helpers/src/subnormals.rs b/crates/test_helpers/src/subnormals.rs +index 44dfbb3..b5f19ba 100644 +--- a/crates/test_helpers/src/subnormals.rs ++++ b/crates/test_helpers/src/subnormals.rs +@@ -39,7 +39,7 @@ macro_rules! impl_else { + } + } + +-impl_float! { f16, f32, f64 } ++impl_float! { f32, f64 } + impl_else! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } + + /// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs. +-- +2.53.0 + From 3bd3fffa7fdcab25692afb45776a1d5fbad620df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2026 17:47:51 +0200 Subject: [PATCH 26/53] float reduce_max/min: fix SNaN treatment (#515) --- crates/core_simd/src/simd/num/float.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 9f27e527f00fc..1fa7991920fa7 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -430,14 +430,14 @@ macro_rules! impl_trait { #[inline] fn reduce_max(self) -> Self::Scalar { - // Safety: `self` is a float vector - unsafe { core::intrinsics::simd::simd_reduce_max(self) } + // LLVM has no intrinsic we can use here + // (https://github.com/llvm/llvm-project/issues/185827). + self.as_array().iter().copied().fold(Self::Scalar::NAN, Self::Scalar::max) } #[inline] fn reduce_min(self) -> Self::Scalar { - // Safety: `self` is a float vector - unsafe { core::intrinsics::simd::simd_reduce_min(self) } + self.as_array().iter().copied().fold(Self::Scalar::NAN, Self::Scalar::min) } } )* From 0afeef0f0de531f978c105bc590a097884a6e4b5 Mon Sep 17 00:00:00 2001 From: Rudraksh Joshi <127816064+0xmuon@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:27:18 +0530 Subject: [PATCH 27/53] fail loudly on unsized by-ref invariants (rust-lang/rustc_codegen_cranelift#1644) replace the remaining todo!() paths for unsized by-ref values in src/value_and_place.rs with explicit bug!() failures. This makes invariant violations fail loudly instead of panicking via unfinished code paths,and without claiming support for unsized by-ref handling that is not actually implemented. --- src/value_and_place.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 5b76a4cb97793..e6d723a954436 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -204,7 +204,9 @@ impl<'tcx> CValue<'tcx> { let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field); CValue::by_ref(field_ptr, field_layout) } - CValueInner::ByRef(_, Some(_)) => todo!(), + CValueInner::ByRef(_, Some(_)) => { + bug!("value_field for unsized by-ref value not supported") + } } } @@ -655,7 +657,13 @@ impl<'tcx> CPlace<'tcx> { flags, ); } - CValueInner::ByRef(_, Some(_)) => todo!(), + CValueInner::ByRef(_from_ptr, Some(_extra)) => { + bug!( + "write_cvalue for unsized by-ref value not allowed: dst={:?} src={:?}", + dst_layout.ty, + from.layout().ty + ); + } } } } From 973ab0a729022a5156588f2064099d855283c4a9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Apr 2026 11:33:00 +0200 Subject: [PATCH 28/53] Rustup to rustc 1.97.0-nightly (7af3402cd 2026-04-16) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7ec491b1b5dd9..bf1db0c1b9ea7 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-04-15" +channel = "nightly-2026-04-17" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From 8591f0f230c44830c16817d8e67c3dc655dfb050 Mon Sep 17 00:00:00 2001 From: Kao-Wei Yeh Date: Wed, 25 Mar 2026 00:13:33 +0800 Subject: [PATCH 29/53] Tweak irrefutable let else warning output, add new suggestion --- compiler/rustc_mir_build/src/errors.rs | 32 +++---- .../src/thir/pattern/check_match.rs | 71 +++++++++++++-- .../let-else/let-else-irrefutable-152938.rs | 2 +- .../let-else-irrefutable-152938.stderr | 18 ++-- tests/ui/let-else/let-else-irrefutable.rs | 12 ++- tests/ui/let-else/let-else-irrefutable.stderr | 47 +++++----- tests/ui/parser/bad-let-else-statement.rs | 16 ++-- tests/ui/parser/bad-let-else-statement.stderr | 89 ++++++------------- tests/ui/span/let-offset-of.rs | 2 +- tests/ui/span/let-offset-of.stderr | 13 ++- 10 files changed, 170 insertions(+), 132 deletions(-) diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 793d9ef18eb61..b7f4fc093b6ba 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -924,22 +924,24 @@ pub(crate) struct IrrefutableLetPatternsIfLetGuard { } #[derive(Diagnostic)] -#[diag( - "irrefutable `let...else` {$count -> - [one] pattern - *[other] patterns -}" -)] -#[note( - "{$count -> - [one] this pattern always matches, so the else clause is unreachable - *[other] these patterns always match, so the else clause is unreachable -}" -)] +#[diag("unreachable `else` clause")] +#[note("this pattern always matches, so the else clause is unreachable")] pub(crate) struct IrrefutableLetPatternsLetElse { - pub(crate) count: usize, - #[help("remove this `else` block")] - pub(crate) else_span: Option, + #[subdiagnostic] + pub(crate) be_replaced: Option, +} + +#[derive(Subdiagnostic, Debug)] +#[suggestion( + "consider using `let {$lhs} = {$rhs}` to match on a specific variant", + code = "let {lhs} = {rhs}", + applicability = "machine-applicable" +)] +pub(crate) struct LetElseReplacementSuggestion { + #[primary_span] + pub(crate) span: Span, + pub(crate) lhs: String, + pub(crate) rhs: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index baabc1afe3fac..3888a297c891c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -168,7 +168,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { let Ok(()) = self.visit_land(ex, &mut chain_refutabilities) else { return }; // Lint only single irrefutable let binding. if let [Some((_, Irrefutable))] = chain_refutabilities[..] { - self.lint_single_let(ex.span, None); + self.lint_single_let(ex.span, None, None); } return; } @@ -438,7 +438,45 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { if let LetSource::PlainLet = self.let_source { self.check_binding_is_irrefutable(pat, "local binding", scrut, Some(span)); } else if let Ok(Irrefutable) = self.is_let_irrefutable(pat, scrut) { - self.lint_single_let(span, else_span); + if span.from_expansion() { + self.lint_single_let(span, None, None); + return; + } + let let_else_span = self.check_irrefutable_option_some(pat, scrut, span); + + let sm = self.tcx.sess.source_map(); + let next_token_start = sm.span_extend_while_whitespace(span.clone()).hi(); + let line_span = sm.span_extend_to_line(span.clone()).with_lo(next_token_start); + let else_keyword_span = sm.span_until_whitespace(line_span); + self.lint_single_let(span, Some(else_keyword_span), let_else_span); + } + } + + /// Check case `let x = Some(y);`, user likely intended to destructure `Option` + fn check_irrefutable_option_some( + &self, + pat: &'p Pat<'tcx>, + initializer: Option<&Expr<'tcx>>, + span: Span, + ) -> Option { + if let sm = self.tcx.sess.source_map() + && let Some(initializer) = initializer + && let Some(s_ty) = initializer.ty.ty_adt_def() + && self.tcx.is_diagnostic_item(rustc_span::sym::Option, s_ty.did()) + && let ExprKind::Scope { value, .. } = initializer.kind + && let initializer_expr = &self.thir[value] + && let ExprKind::Adt(box AdtExpr { fields, .. }) = &initializer_expr.kind + && let Some(field) = fields.first() + && let inner = &self.thir[field.expr] + && let Some(inner_ty) = inner.ty.ty_adt_def() + && self.tcx.is_diagnostic_item(rustc_span::sym::Option, inner_ty.did()) + && let Ok(rhs) = sm.span_to_snippet(inner.span) + && let Ok(lhs) = sm.span_to_snippet(pat.span) + { + let lhs = format!("Some({})", lhs); + Some(LetElseReplacementSuggestion { span, lhs, rhs }) + } else { + None } } @@ -546,14 +584,20 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { } #[instrument(level = "trace", skip(self))] - fn lint_single_let(&mut self, let_span: Span, else_span: Option) { + fn lint_single_let( + &mut self, + let_span: Span, + else_keyword_span: Option, + let_else_span: Option, + ) { report_irrefutable_let_patterns( self.tcx, self.hir_source, self.let_source, 1, let_span, - else_span, + else_keyword_span, + let_else_span, ); } @@ -849,7 +893,8 @@ fn report_irrefutable_let_patterns( source: LetSource, count: usize, span: Span, - else_span: Option, + else_keyword_span: Option, + let_else_span: Option, ) { macro_rules! emit_diag { ($lint:tt) => {{ @@ -862,11 +907,23 @@ fn report_irrefutable_let_patterns( LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => { + let spans = match else_keyword_span { + Some(else_keyword_span) => { + let mut spans = MultiSpan::from_span(else_keyword_span); + spans.push_span_label( + span, + msg!("assigning to binding pattern will always succeed"), + ); + spans + } + None => span.into(), + }; + tcx.emit_node_span_lint( IRREFUTABLE_LET_PATTERNS, id, - span, - IrrefutableLetPatternsLetElse { count, else_span }, + spans, + IrrefutableLetPatternsLetElse { be_replaced: let_else_span }, ); } LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet), diff --git a/tests/ui/let-else/let-else-irrefutable-152938.rs b/tests/ui/let-else/let-else-irrefutable-152938.rs index 6e0ffe3fb8706..25e3e0f6e5708 100644 --- a/tests/ui/let-else/let-else-irrefutable-152938.rs +++ b/tests/ui/let-else/let-else-irrefutable-152938.rs @@ -6,7 +6,7 @@ pub fn say_hello(name: Option) { let name_str = Some(name) else { return; }; - //~^ WARN irrefutable `let...else` pattern + //~^ WARN unreachable `else` clause drop(name_str); } diff --git a/tests/ui/let-else/let-else-irrefutable-152938.stderr b/tests/ui/let-else/let-else-irrefutable-152938.stderr index 57632964be9b3..e32f4960a3350 100644 --- a/tests/ui/let-else/let-else-irrefutable-152938.stderr +++ b/tests/ui/let-else/let-else-irrefutable-152938.stderr @@ -1,16 +1,18 @@ -warning: irrefutable `let...else` pattern - --> $DIR/let-else-irrefutable-152938.rs:8:5 +warning: unreachable `else` clause + --> $DIR/let-else-irrefutable-152938.rs:8:31 | LL | let name_str = Some(name) else { return; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------- ^^^^ + | | + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/let-else-irrefutable-152938.rs:8:36 - | -LL | let name_str = Some(name) else { return; }; - | ^^^^^^^^^^^ = note: `#[warn(irrefutable_let_patterns)]` on by default +help: consider using `let Some(name_str) = name` to match on a specific variant + | +LL - let name_str = Some(name) else { return; }; +LL + let Some(name_str) = name else { return; }; + | warning: 1 warning emitted diff --git a/tests/ui/let-else/let-else-irrefutable.rs b/tests/ui/let-else/let-else-irrefutable.rs index f9675ff5938eb..59de726d38ddf 100644 --- a/tests/ui/let-else/let-else-irrefutable.rs +++ b/tests/ui/let-else/let-else-irrefutable.rs @@ -1,10 +1,18 @@ //@ check-pass fn main() { - let x = 1 else { return }; //~ WARN irrefutable `let...else` pattern + let x = 1 else { return }; //~ WARN unreachable `else` clause // Multiline else blocks should not get printed - let x = 1 else { //~ WARN irrefutable `let...else` pattern + let x = 1 else { //~ WARN unreachable `else` clause + eprintln!("problem case encountered"); + return + }; + + let case = Some("a"); + let name = Some(case) else { + //~^ WARN unreachable `else` clause + //~| HELP consider using `let Some(name) = case` to match on a specific variant eprintln!("problem case encountered"); return }; diff --git a/tests/ui/let-else/let-else-irrefutable.stderr b/tests/ui/let-else/let-else-irrefutable.stderr index d36d227b4156a..12338789d2a03 100644 --- a/tests/ui/let-else/let-else-irrefutable.stderr +++ b/tests/ui/let-else/let-else-irrefutable.stderr @@ -1,33 +1,38 @@ -warning: irrefutable `let...else` pattern - --> $DIR/let-else-irrefutable.rs:4:5 +warning: unreachable `else` clause + --> $DIR/let-else-irrefutable.rs:4:15 | LL | let x = 1 else { return }; - | ^^^^^^^^^ + | --------- ^^^^ + | | + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/let-else-irrefutable.rs:4:20 - | -LL | let x = 1 else { return }; - | ^^^^^^^^^^ = note: `#[warn(irrefutable_let_patterns)]` on by default -warning: irrefutable `let...else` pattern - --> $DIR/let-else-irrefutable.rs:7:5 +warning: unreachable `else` clause + --> $DIR/let-else-irrefutable.rs:7:15 | LL | let x = 1 else { - | ^^^^^^^^^ + | --------- ^^^^ + | | + | assigning to binding pattern will always succeed + | + = note: this pattern always matches, so the else clause is unreachable + +warning: unreachable `else` clause + --> $DIR/let-else-irrefutable.rs:13:27 + | +LL | let name = Some(case) else { + | --------------------- ^^^^ + | | + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/let-else-irrefutable.rs:7:20 - | -LL | let x = 1 else { - | ____________________^ -LL | | eprintln!("problem case encountered"); -LL | | return -LL | | }; - | |_____^ +help: consider using `let Some(name) = case` to match on a specific variant + | +LL - let name = Some(case) else { +LL + let Some(name) = case else { + | -warning: 2 warnings emitted +warning: 3 warnings emitted diff --git a/tests/ui/parser/bad-let-else-statement.rs b/tests/ui/parser/bad-let-else-statement.rs index 3ede26dbcd06c..a552fbcfc1fc3 100644 --- a/tests/ui/parser/bad-let-else-statement.rs +++ b/tests/ui/parser/bad-let-else-statement.rs @@ -93,10 +93,10 @@ fn i() { fn j() { let mut bar = 0; let foo = bar = { - //~^ WARN irrefutable `let...else` pattern 1 } else { - //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + //~^ WARN unreachable `else` clause + //~| ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; }; } @@ -158,21 +158,21 @@ fn o() -> Result<(), ()> { fn q() { let foo = |x: i32| { - //~^ WARN irrefutable `let...else` pattern x } else { - //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + //~^ WARN unreachable `else` clause + //~| ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; }; } fn r() { let ok = format_args!("") else { return; }; - //~^ WARN irrefutable `let...else` pattern + //~^ WARN unreachable `else` clause let bad = format_args! {""} else { return; }; //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed - //~| WARN irrefutable `let...else` pattern + //~| WARN unreachable `else` clause } fn s() { @@ -202,10 +202,10 @@ fn t() { } let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! { - //~^ WARN irrefutable `let...else` pattern 8 } else { - //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed + //~^ WARN unreachable `else` clause + //~| ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; }; } diff --git a/tests/ui/parser/bad-let-else-statement.stderr b/tests/ui/parser/bad-let-else-statement.stderr index 8545d95f507f6..76fbbbb8c1e10 100644 --- a/tests/ui/parser/bad-let-else-statement.stderr +++ b/tests/ui/parser/bad-let-else-statement.stderr @@ -125,7 +125,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:98:5 + --> $DIR/bad-let-else-statement.rs:97:5 | LL | } else { | ^ @@ -133,7 +133,6 @@ LL | } else { help: wrap the expression in parentheses | LL ~ let foo = bar = ({ -LL | LL | 1 LL ~ }) else { | @@ -204,7 +203,7 @@ LL ~ }) else { | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:163:5 + --> $DIR/bad-let-else-statement.rs:162:5 | LL | } else { | ^ @@ -212,7 +211,6 @@ LL | } else { help: wrap the expression in parentheses | LL ~ let foo = |x: i32| ({ -LL | LL | x LL ~ }) else { | @@ -230,7 +228,7 @@ LL + let bad = format_args! ("") else { return; }; | error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/bad-let-else-statement.rs:207:5 + --> $DIR/bad-let-else-statement.rs:206:5 | LL | } else { | ^ @@ -238,7 +236,6 @@ LL | } else { help: use parentheses instead of braces for this macro | LL ~ let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! ( -LL | LL | 8 LL ~ ) else { | @@ -259,92 +256,62 @@ LL - let 0 = a! {} else { return; }; LL + let 0 = a! () else { return; }; | -warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:95:5 +warning: unreachable `else` clause + --> $DIR/bad-let-else-statement.rs:97:7 | LL | / let foo = bar = { -LL | | LL | | 1 LL | | } else { - | |_____^ + | | - ^^^^ + | |_____| + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/bad-let-else-statement.rs:98:12 - | -LL | } else { - | ____________^ -LL | | -LL | | return; -LL | | }; - | |_____^ = note: `#[warn(irrefutable_let_patterns)]` on by default -warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:160:5 +warning: unreachable `else` clause + --> $DIR/bad-let-else-statement.rs:162:7 | LL | / let foo = |x: i32| { -LL | | LL | | x LL | | } else { - | |_____^ + | | - ^^^^ + | |_____| + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/bad-let-else-statement.rs:163:12 - | -LL | } else { - | ____________^ -LL | | -LL | | return; -LL | | }; - | |_____^ -warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:170:5 +warning: unreachable `else` clause + --> $DIR/bad-let-else-statement.rs:170:31 | LL | let ok = format_args!("") else { return; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------- ^^^^ + | | + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/bad-let-else-statement.rs:170:36 - | -LL | let ok = format_args!("") else { return; }; - | ^^^^^^^^^^^ -warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:173:5 +warning: unreachable `else` clause + --> $DIR/bad-let-else-statement.rs:173:33 | LL | let bad = format_args! {""} else { return; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------------------- ^^^^ + | | + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/bad-let-else-statement.rs:173:38 - | -LL | let bad = format_args! {""} else { return; }; - | ^^^^^^^^^^^ -warning: irrefutable `let...else` pattern - --> $DIR/bad-let-else-statement.rs:204:5 +warning: unreachable `else` clause + --> $DIR/bad-let-else-statement.rs:206:7 | LL | / let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! { -LL | | LL | | 8 LL | | } else { - | |_____^ + | | - ^^^^ + | |_____| + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/bad-let-else-statement.rs:207:12 - | -LL | } else { - | ____________^ -LL | | -LL | | return; -LL | | }; - | |_____^ error: aborting due to 19 previous errors; 5 warnings emitted diff --git a/tests/ui/span/let-offset-of.rs b/tests/ui/span/let-offset-of.rs index 99b34a1928470..eeecf38e6b6a9 100644 --- a/tests/ui/span/let-offset-of.rs +++ b/tests/ui/span/let-offset-of.rs @@ -15,5 +15,5 @@ fn init_to_offset_of() { //~^ WARN irrefutable `if let` pattern let x = offset_of!(Foo, field) else { return; }; - //~^ WARN irrefutable `let...else` pattern + //~^ WARN unreachable `else` clause } diff --git a/tests/ui/span/let-offset-of.stderr b/tests/ui/span/let-offset-of.stderr index df9b1e695b1e4..afcf8a8103d9d 100644 --- a/tests/ui/span/let-offset-of.stderr +++ b/tests/ui/span/let-offset-of.stderr @@ -8,18 +8,15 @@ LL | if let x = offset_of!(Foo, field) {} = help: consider replacing the `if let` with a `let` = note: `#[warn(irrefutable_let_patterns)]` on by default -warning: irrefutable `let...else` pattern - --> $DIR/let-offset-of.rs:17:5 +warning: unreachable `else` clause + --> $DIR/let-offset-of.rs:17:36 | LL | let x = offset_of!(Foo, field) else { return; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------ ^^^^ + | | + | assigning to binding pattern will always succeed | = note: this pattern always matches, so the else clause is unreachable -help: remove this `else` block - --> $DIR/let-offset-of.rs:17:41 - | -LL | let x = offset_of!(Foo, field) else { return; }; - | ^^^^^^^^^^^ warning: 2 warnings emitted From 3d2e5934dd8c2c48f68ffc5ea2109e50e36d40f8 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Wed, 15 Apr 2026 12:17:20 +0800 Subject: [PATCH 30/53] fix all errors --- src/debuginfo/mod.rs | 6 +++++- src/main_shim.rs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 756f86a7d0111..6ab5c5088e55a 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -19,6 +19,7 @@ use indexmap::IndexSet; use rustc_codegen_ssa::debuginfo::type_names; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; +use rustc_middle::ty::Unnormalized; use rustc_session::Session; use rustc_session::config::DebugInfo; use rustc_span::{RemapPathScopeComponents, SourceFileHash, StableSourceFileId}; @@ -244,7 +245,10 @@ impl DebugContext { type_names::push_generic_args( tcx, - tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args), + tcx.normalize_erasing_regions( + ty::TypingEnv::fully_monomorphized(), + Unnormalized::new_wip(args), + ), &mut name, ); diff --git a/src/main_shim.rs b/src/main_shim.rs index c3e4bf1f0c275..dd776f9cfcaee 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -1,6 +1,6 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; -use rustc_middle::ty::{AssocTag, GenericArg}; +use rustc_middle::ty::{AssocTag, GenericArg, Unnormalized}; use rustc_session::config::EntryFnType; use rustc_span::{DUMMY_SP, Ident}; @@ -50,7 +50,7 @@ pub(crate) fn maybe_create_entry_wrapper( // listing. let main_ret_ty = tcx.normalize_erasing_regions( ty::TypingEnv::fully_monomorphized(), - main_ret_ty.no_bound_vars().unwrap(), + Unnormalized::new_wip(main_ret_ty.no_bound_vars().unwrap()), ); let cmain_sig = Signature { From af2b606baa384f7488d9d9e29639550a7a095575 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:46:07 +0200 Subject: [PATCH 31/53] Rustup to rustc 1.97.0-nightly (e22c616e4 2026-04-19) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index bf1db0c1b9ea7..42db240bc4f86 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-04-17" +channel = "nightly-2026-04-20" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From 720aed373a6e31583c10681384a06143c5d64a95 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:09:48 +0200 Subject: [PATCH 32/53] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 71ff4eef071c3..0b7e308b9489f 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -50,6 +50,7 @@ rm tests/ui/c-variadic/copy.rs # same rm tests/ui/sanitizer/kcfi-c-variadic.rs # same rm tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs # variadics for calling conventions other than C unsupported rm tests/ui/delegation/fn-header.rs +rm tests/ui/c-variadic/roundtrip.rs # inline assembly features rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly @@ -144,6 +145,7 @@ rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift rm -r tests/run-make/short-ice # ICE backtrace begin/end marker mismatch +rm -r tests/run-make/naked-dead-code-elimination # function not eliminated # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended From f7893ba153232b3fbf52e2b03e1c1f4407d000ee Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 20 Apr 2026 17:00:51 +0200 Subject: [PATCH 33/53] add `f16` types to the prelude (#521) --- crates/core_simd/src/simd/prelude.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/core_simd/src/simd/prelude.rs b/crates/core_simd/src/simd/prelude.rs index 6e93f16e10b1c..51b8def3d6eed 100644 --- a/crates/core_simd/src/simd/prelude.rs +++ b/crates/core_simd/src/simd/prelude.rs @@ -14,6 +14,10 @@ pub use super::{ simd_swizzle, }; +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{f16x1, f16x2, f16x4, f16x8, f16x16, f16x32, f16x64}; + #[rustfmt::skip] #[doc(no_inline)] pub use super::{f32x1, f32x2, f32x4, f32x8, f32x16, f32x32, f32x64}; From 10fba0bdce0d1b5b035a19959be9e433aa43e743 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 21 Apr 2026 13:12:36 +1000 Subject: [PATCH 34/53] Update to Cranelift 0.130 --- Cargo.lock | 76 +++++++++++++++++++++++----------------------- Cargo.toml | 26 ++++++++-------- src/pretty_clif.rs | 8 +---- 3 files changed, 52 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d84d2c57fc6b..979ae1be3c28b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,27 +43,27 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cranelift-assembler-x64" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f248321c6a7d4de5dcf2939368e96a397ad3f53b6a076e38d0104d1da326d37" +checksum = "6edb5bdd1af46714e3224a017fabbbd57f70df4e840eb5ad6a7429dc456119d6" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab6d78ff1f7d9bf8b7e1afbedbf78ba49e38e9da479d4c8a2db094e22f64e2bc" +checksum = "a819599186e1b1a1f88d464e06045696afc7aa3e0cc018aa0b2999cb63d1d088" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b6005ba640213a5b95382aeaf6b82bf028309581c8d7349778d66f27dc1180b" +checksum = "36e2c152d488e03c87b913bc2ed3414416eb1e0d66d61b49af60bf456a9665c7" dependencies = [ "cranelift-entity", "wasmtime-internal-core", @@ -71,18 +71,18 @@ dependencies = [ [[package]] name = "cranelift-bitset" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fb5b134a12b559ff0c0f5af0fcd755ad380723b5016c4e0d36f74d39485340" +checksum = "b6559d4fbc253d1396e1f6beeae57fa88a244f02aaf0cde2a735afd3492d9b2e" dependencies = [ "wasmtime-internal-core", ] [[package]] name = "cranelift-codegen" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85837de8be7f17a4034a6b08816f05a3144345d2091937b39d415990daca28f4" +checksum = "96d9315d98d6e0a64454d4c83be2ee0e8055c3f80c3b2d7bcad7079f281a06ff" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e433faa87d38e5b8ff469e44a26fea4f93e58abd7a7c10bad9810056139700c9" +checksum = "d89c00a88081c55e3087c45bebc77e0cc973de2d7b44ef6a943c7122647b89f5" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -119,24 +119,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5397ba61976e13944ca71230775db13ee1cb62849701ed35b753f4761ed0a9b7" +checksum = "879f77c497a1eb6273482aa1ac3b23cb8563ff04edb39ed5dfcfd28c8deff8f5" [[package]] name = "cranelift-control" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc81c88765580720eb30f4fc2c1bfdb75fcbf3094f87b3cd69cecca79d77a245" +checksum = "498dc1f17a6910c88316d49c7176d8fa97cf10c30859c32a266040449317f963" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463feed5d46cf8763f3ba3045284cf706dd161496e20ec9c14afbb4ba09b9e66" +checksum = "c2acba797f6a46042ce82aaf7680d0c3567fe2001e238db9df649fd104a2727f" dependencies = [ "cranelift-bitset", "wasmtime-internal-core", @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c5eca7696c1c04ab4c7ed8d18eadbb47d6cc9f14ec86fe0881bf1d7e97e261" +checksum = "4dca3df1d107d98d88f159ad1d5eaa2d5cdb678b3d5bcfadc6fc83d8ebb448ea" dependencies = [ "cranelift-codegen", "log", @@ -156,15 +156,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1153844610cc9c6da8cf10ce205e45da1a585b7688ed558aa808bbe2e4e6d77" +checksum = "f62dd18116d88bed649871feceda79dad7b59cc685ea8998c2b3e64d0e689602" [[package]] name = "cranelift-jit" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41836de8321b303d3d4188e58cc09c30c7645337342acfcfb363732695cae098" +checksum = "0a4942770ce6662b44d903493d7c5b00f9a986a713a61aae148306eaef21ebd4" dependencies = [ "anyhow", "cranelift-codegen", @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b731f66cb1b69b60a74216e632968ebdbb95c488d26aa1448ec226ae0ffec33e" +checksum = "fb5ca0d214ecee44405ea9f0c65a5318b41ac469e8258fd9fe944e564c1c1b0b" dependencies = [ "anyhow", "cranelift-codegen", @@ -193,9 +193,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97b583fe9a60f06b0464cee6be5a17f623fd91b217aaac99b51b339d19911af" +checksum = "f843b80360d7fdf61a6124642af7597f6d55724cf521210c34af8a1c66daca6e" dependencies = [ "cranelift-codegen", "libc", @@ -204,9 +204,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9809d2d419cd18f17377f4ce64a7ad22eeda0d042c08833d3796657f1ddebc82" +checksum = "b9d212d15015c374333b11b833111b7c7e686bfaec02385af53611050bce7e9d" dependencies = [ "anyhow", "cranelift-codegen", @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8594dc6bb4860fa8292f1814c76459dbfb933e1978d8222de6380efce45c7cee" +checksum = "090ee5de58c6f17eb5e3a5ae8cf1695c7efea04ec4dd0ecba6a5b996c9bad7dc" [[package]] name = "crc32fast" @@ -338,9 +338,9 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "object" -version = "0.38.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" +checksum = "63944c133d03f44e75866bbd160b95af0ec3f6a13d936d69d31c81078cbc5baf" dependencies = [ "crc32fast", "hashbrown 0.16.1", @@ -482,9 +482,9 @@ checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "wasmtime-internal-core" -version = "43.0.0" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e671917bb6856ae360cb59d7aaf26f1cfd042c7b924319dd06fd380739fc0b2e" +checksum = "816a61a75275c6be435131fc625a4f5956daf24d9f9f59443e81cbef228929b3" dependencies = [ "hashbrown 0.16.1", "libm", @@ -492,9 +492,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "43.0.0" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3112806515fac8495883885eb8dbdde849988ae91fe6beb544c0d7c0f4c9aa" +checksum = "2fd683a94490bf755d016a09697b0955602c50106b1ded97d16983ab2ded9fed" dependencies = [ "cfg-if", "libc", diff --git a/Cargo.toml b/Cargo.toml index 6707557f06f75..0564a8f4ba627 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.130.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.130.0" } -cranelift-module = { version = "0.130.0" } -cranelift-native = { version = "0.130.0" } -cranelift-jit = { version = "0.130.0", optional = true } -cranelift-object = { version = "0.130.0" } +cranelift-codegen = { version = "0.131.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.131.0" } +cranelift-module = { version = "0.131.0" } +cranelift-native = { version = "0.131.0" } +cranelift-jit = { version = "0.131.0", optional = true } +cranelift-object = { version = "0.131.0" } target-lexicon = "0.13" gimli = { version = "0.33", default-features = false, features = ["write"] } -object = { version = "0.38.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.39.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.9.0", optional = true } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-44.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-44.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-44.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-44.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-44.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-44.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 65779b38ad1c0..918fe3d2a3895 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -60,7 +60,6 @@ use std::fmt; use std::io::Write; use cranelift_codegen::entity::SecondaryMap; -use cranelift_codegen::ir::Fact; use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::write::{FuncWriter, PlainWriter}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -182,13 +181,8 @@ impl FuncWriter for &'_ CommentWriter { _func: &Function, entity: AnyEntity, value: &dyn fmt::Display, - maybe_fact: Option<&Fact>, ) -> fmt::Result { - if let Some(fact) = maybe_fact { - write!(w, " {} ! {} = {}", entity, fact, value)?; - } else { - write!(w, " {} = {}", entity, value)?; - } + write!(w, " {} = {}", entity, value)?; if let Some(comment) = self.entity_comments.get(&entity) { writeln!(w, " ; {}", comment.replace('\n', "\n; ")) From 04564d165ffadb6f4a4136ab46ed5bdd8875a4f1 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 21 Apr 2026 13:18:10 +1000 Subject: [PATCH 35/53] Update to object 0.39.1 --- Cargo.lock | 21 +++++++++++++++------ Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 979ae1be3c28b..ca623eabaa2d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,6 +277,15 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +dependencies = [ + "foldhash", +] + [[package]] name = "heck" version = "0.5.0" @@ -285,12 +294,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", ] [[package]] @@ -338,12 +347,12 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "object" -version = "0.39.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63944c133d03f44e75866bbd160b95af0ec3f6a13d936d69d31c81078cbc5baf" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" dependencies = [ "crc32fast", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "indexmap", "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 0564a8f4ba627..b775809a50e3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ cranelift-jit = { version = "0.131.0", optional = true } cranelift-object = { version = "0.131.0" } target-lexicon = "0.13" gimli = { version = "0.33", default-features = false, features = ["write"] } -object = { version = "0.39.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.39.1", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.9.0", optional = true } From a0871ed21b6be9cd1913ffad80f9e867f4547846 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 21 Apr 2026 18:45:55 +1000 Subject: [PATCH 36/53] Fix __eh_frame for AArch64 on macOS The relocations must use symbols (not sections), and the relative relocation needs ARM64_RELOC_SUBTRACTOR. The section must be in __TEXT rather than __DWARF, which is handled by using StandardSection::EhFrame. This also changes the section type for ELF x86-64. --- src/debuginfo/emit.rs | 2 +- src/debuginfo/object.rs | 54 +++++++++++++++++++++++------------------ src/debuginfo/unwind.rs | 12 ++++----- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index 8016c5a3005a2..cc1efef287517 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -43,7 +43,7 @@ impl DebugContext { let _: Result<()> = sections.for_each(|id, section| { if let Some(section_id) = section_map.get(&id) { for reloc in §ion.relocs { - product.add_debug_reloc(§ion_map, section_id, reloc); + product.add_debug_reloc(§ion_map, section_id, reloc, true); } } Ok(()) diff --git a/src/debuginfo/object.rs b/src/debuginfo/object.rs index 1c6e471cc870f..0af03ff33a43e 100644 --- a/src/debuginfo/object.rs +++ b/src/debuginfo/object.rs @@ -1,7 +1,7 @@ use cranelift_module::{DataId, FuncId}; use cranelift_object::ObjectProduct; use gimli::SectionId; -use object::write::{Relocation, StandardSegment}; +use object::write::{Relocation, StandardSection, StandardSegment}; use object::{RelocationEncoding, RelocationFlags, SectionKind}; use rustc_data_structures::fx::FxHashMap; @@ -16,6 +16,7 @@ pub(super) trait WriteDebugInfo { section_map: &FxHashMap, from: &Self::SectionId, reloc: &DebugReloc, + use_section_symbol: bool, ); } @@ -27,29 +28,31 @@ impl WriteDebugInfo for ObjectProduct { id: SectionId, data: Vec, ) -> (object::write::SectionId, object::write::SymbolId) { - let name = if self.object.format() == object::BinaryFormat::MachO { - id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info + let (section_id, align); + if id == SectionId::EhFrame { + section_id = self.object.section_id(StandardSection::EhFrame); + align = 8; } else { - id.name().to_string() - } - .into_bytes(); - - let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); - // FIXME use SHT_X86_64_UNWIND for .eh_frame - let section_id = self.object.add_section( - segment, - name, - if id == SectionId::DebugStr || id == SectionId::DebugLineStr { - SectionKind::DebugString - } else if id == SectionId::EhFrame { - SectionKind::ReadOnlyData + let name = if self.object.format() == object::BinaryFormat::MachO { + id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info } else { - SectionKind::Debug - }, - ); - self.object - .section_mut(section_id) - .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); + id.name().to_string() + } + .into_bytes(); + + let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); + section_id = self.object.add_section( + segment, + name, + if id == SectionId::DebugStr || id == SectionId::DebugLineStr { + SectionKind::DebugString + } else { + SectionKind::Debug + }, + ); + align = 1; + } + self.object.section_mut(section_id).set_data(data, align); let symbol_id = self.object.section_symbol(section_id); (section_id, symbol_id) } @@ -59,6 +62,7 @@ impl WriteDebugInfo for ObjectProduct { section_map: &FxHashMap, from: &Self::SectionId, reloc: &DebugReloc, + use_section_symbol: bool, ) { let (symbol, symbol_offset) = match reloc.name { DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), @@ -69,7 +73,11 @@ impl WriteDebugInfo for ObjectProduct { } else { self.data_symbol(DataId::from_u32(id & !(1 << 31))) }; - self.object.symbol_section_and_offset(symbol_id).unwrap_or((symbol_id, 0)) + if use_section_symbol { + self.object.symbol_section_and_offset(symbol_id).unwrap_or((symbol_id, 0)) + } else { + (symbol_id, 0) + } } }; self.object diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 33ffe4cc4e9c8..1ce424332db20 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -120,13 +120,12 @@ impl UnwindContext { func_id: FuncId, context: &Context, ) { - if let target_lexicon::OperatingSystem::MacOSX { .. } = - module.isa().triple().operating_system + let triple = module.isa().triple(); + if matches!(triple.operating_system, target_lexicon::OperatingSystem::MacOSX { .. }) + && triple.architecture == target_lexicon::Architecture::X86_64 { // The object crate doesn't currently support DW_GNU_EH_PE_absptr, which macOS - // requires for unwinding tables. In addition on arm64 it currently doesn't - // support 32bit relocations as we currently use for the unwinding table. - // See gimli-rs/object#415 and rust-lang/rustc_codegen_cranelift#1371 + // requires for unwinding tables. See gimli-rs/object#415. return; } @@ -250,8 +249,9 @@ impl UnwindContext { let mut section_map = FxHashMap::default(); section_map.insert(id, section_id); + let use_section_symbol = product.object.format() != object::BinaryFormat::MachO; for reloc in &eh_frame.0.relocs { - product.add_debug_reloc(§ion_map, §ion_id, reloc); + product.add_debug_reloc(§ion_map, §ion_id, reloc, use_section_symbol); } } } From e6e77ab00c360cda5e6c4323735a15d43c387cea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:03:28 +0200 Subject: [PATCH 37/53] Temporarily allow releases when the bench job fails The bench job is broken because of a cargo regression. --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7f9fd0cc7c5e0..a3ab9a91e3a8b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -242,7 +242,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/main' }} - needs: [todo_check, rustfmt, test, bench, dist] + # FIXME add bench back once rust-lang/cargo#16925 has been fixed + needs: [todo_check, rustfmt, test, dist] permissions: contents: write # for creating the dev tag and release From 9447da6f88b2f6cf22cbf7d01b3cc19978967001 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Thu, 23 Apr 2026 15:04:48 -0400 Subject: [PATCH 38/53] Add bound check hint to mask first_set (#523) --- crates/core_simd/src/masks.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/core_simd/src/masks.rs b/crates/core_simd/src/masks.rs index a5334afbe5f8b..cb5d54020f7fc 100644 --- a/crates/core_simd/src/masks.rs +++ b/crates/core_simd/src/masks.rs @@ -400,7 +400,15 @@ where if min_index.eq(T::TRUE) { None } else { - Some(min_index.to_usize()) + let min_index = min_index.to_usize(); + + // Allow eliminating bounds checks when using the index + // Safety: the index can't exceed the number of elements in the vector + unsafe { + core::hint::assert_unchecked(min_index < N); + } + + Some(min_index) } } } From 3c362ecfa67ff5252f0acfce045f93f1ec500637 Mon Sep 17 00:00:00 2001 From: Arjun Ramesh Date: Fri, 24 Apr 2026 12:19:55 -0400 Subject: [PATCH 39/53] Update documentation for `wasm32-wali-linux-musl` after integrating new LLVM 22 `wasm32-linux-muslwali` target changes --- .../src/platform-support/wasm32-wali-linux.md | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md index 001159b0d3266..f434c9e94867f 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md +++ b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md @@ -15,7 +15,7 @@ From the wider Wasm ecosystem perspective, implementing WALI within engines allo ## Requirements ### Compilation -This target is cross-compiled and requires an installation of the [WALI compiler/sysroot](https://github.com/arjunr2/WALI). This produces standard `wasm32` binaries with the WALI interface methods as module imports that need to be implemented by a supported engine (see the "Execution" section below). +This target is cross-compiled and requires an installation of the [WALI sysroot](https://github.com/Wasm-Thin-Kernel-Interfaces/WALI.git). This produces standard `wasm32` binaries with the WALI interface methods as module imports that need to be implemented by a supported engine (see the "Execution" section below). `wali` targets *minimally require* the following LLVM feature flags: @@ -31,7 +31,7 @@ This target is cross-compiled and requires an installation of the [WALI compiler > **Note**: Users can expect that new enabled-by-default Wasm features for LLVM are transitively incorporatable into this target -- see [wasm32-unknown-unknown](wasm32-unknown-unknown.md) for detailed information on WebAssembly features. -> **Note**: The WALI ABI is similar to default Clang wasm32 ABIs but *not identical*. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to maintain minimum source code changes for 64-bit host platforms currently supported. This may change in the future as the spec evolves. +> **Note**: The WALI ABI is *not identical* to the default Clang wasm32 ABI. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to maximize portability with minimum source code changes for currently supported 64-bit host platforms. These ABIs may converge in the future as the spec evolves. ### Execution Running generated WALI binaries also requires a supported compliant engine implementation -- a working implementation in the [WebAssembly Micro-Runtime (WAMR)](https://github.com/arjunr2/WALI) is included in the repo. @@ -41,38 +41,28 @@ Running generated WALI binaries also requires a supported compliant engine imple ## Building the target You can build Rust with support for the target by adding it to the `target` -list in `config.toml`, and pointing to the toolchain artifacts from the previous section ("Requirements->Compilation"). A sample `config.toml` for the `musl` environment will look like this, where `` is the absolute path to the root directory of the [WALI repo](https://github.com/arjunr2/WALI): +list in `bootstrap.toml`, and pointing to the toolchain artifacts from the previous section ("Requirements->Compilation"). A sample `bootstrap.toml` for the `musl` environment will look like this, where `` is the absolute path to the root directory of the [WALI repo](https://github.com/arjunr2/WALI): ```toml [build] target = ["wasm32-wali-linux-musl"] [target.wasm32-wali-linux-musl] -musl-root = "/wali-musl/sysroot" -llvm-config = "/llvm-project/build/bin/llvm-config" -cc = "/llvm-project/build/bin/clang-18" -cxx = "/llvm-project/build/bin/clang-18" -ar = "/llvm-project/build/bin/llvm-ar" -ranlib = "/llvm-project/build/bin/llvm-ranlib" +musl-root = "/build/sysroot" +cc = "/build/llvm/bin/clang" +cxx = "/build/llvm/bin/clang++" +ar = "/build/llvm/bin/llvm-ar" +ranlib = "/build/llvm/bin/llvm-ranlib" llvm-libunwind = "system" crt-static = true ``` -> The `llvm-config` settings are only temporary, and the changes will eventually be upstreamed into LLVM - ## Building Rust programs Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using -`build-std` or similar. - -Rust program builds can use this target normally. Currently, linking WALI programs may require pointing the `linker` to the llvm build in the [Cargo config](https://doc.rust-lang.org/cargo/reference/config.html) (until LLVM is upstreamed). A `config.toml` for Cargo will look like the following: - -```toml -[target.wasm32-wali-linux-musl] -linker = "/llvm-project/build/bin/lld" -``` +`build-std` or similar (with the appropriate sysroot links). Note that the following `cfg` directives are set for `wasm32-wali-linux-*`: From c20757fd30dee33aa6bc65cff83dfe920463f202 Mon Sep 17 00:00:00 2001 From: Arjun Ramesh Date: Fri, 24 Apr 2026 16:25:47 -0400 Subject: [PATCH 40/53] Add specific target diffs --- src/doc/rustc/src/platform-support/wasm32-wali-linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md index f434c9e94867f..c87cc1d5f863d 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md +++ b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md @@ -31,7 +31,7 @@ This target is cross-compiled and requires an installation of the [WALI sysroot] > **Note**: Users can expect that new enabled-by-default Wasm features for LLVM are transitively incorporatable into this target -- see [wasm32-unknown-unknown](wasm32-unknown-unknown.md) for detailed information on WebAssembly features. -> **Note**: The WALI ABI is *not identical* to the default Clang wasm32 ABI. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to maximize portability with minimum source code changes for currently supported 64-bit host platforms. These ABIs may converge in the future as the spec evolves. +> **Note**: The WALI ABI is *not identical* to the `wasm32-wasip2` or `wasm32-unknown-unknown` ABI. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to maximize portability with minimum source code changes for currently supported 64-bit host platforms. These ABIs may converge in the future as the spec evolves. ### Execution Running generated WALI binaries also requires a supported compliant engine implementation -- a working implementation in the [WebAssembly Micro-Runtime (WAMR)](https://github.com/arjunr2/WALI) is included in the repo. From da0fe8db677a4f0915b8f362a99978e93dc843ed Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 24 Apr 2026 13:11:16 +1000 Subject: [PATCH 41/53] Overhaul the code for running an incremental test revision The main goals of this overhaul are: - Introduce a dedicated `IncrRevKind` enum for exhaustive matching. - Eliminate any dependency on `PassMode` and `FailMode`. - Use a single code path for all incremental revision kinds. Separating incremental tests from the existing pass/fail enums should make it easier to overhaul the implementation of pass/fail expectations in UI tests. --- src/tools/compiletest/src/runtest.rs | 14 -- .../compiletest/src/runtest/incremental.rs | 166 ++++++++++-------- 2 files changed, 89 insertions(+), 91 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 568e307366641..ab268f944816f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -319,20 +319,6 @@ impl<'test> TestCx<'test> { TestMode::RustdocJs => true, TestMode::Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build), TestMode::Crashes => false, - TestMode::Incremental => { - let revision = - self.revision.expect("incremental tests require a list of revisions"); - if revision.starts_with("cpass") - || revision.starts_with("bpass") - || revision.starts_with("rpass") - { - true - } else if revision.starts_with("bfail") { - false - } else { - panic!("revision name must begin with `cpass`, `bfail`, `bpass`, or `rpass`"); - } - } mode => panic!("unimplemented for mode {:?}", mode), } } diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 85e0c89a8d018..6529882715a90 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -1,26 +1,43 @@ -use super::{Emit, FailMode, PassMode, ProcRes, TestCx, WillExecute}; +use std::sync::LazyLock; + +use crate::runtest::{Emit, TestCx, WillExecute}; +use crate::util::string_enum; + +string_enum!( + /// How far an incremental test revision should proceed through the compile/run + /// sequence, and whether the last step should succeed or fail, as determined + /// from the start of the revision name. + #[derive(Clone, Copy, PartialEq, Eq)] + enum IncrRevKind { + CheckPass => "cpass", + BuildFail => "bfail", + BuildPass => "bpass", + RunPass => "rpass", + } +); + +impl IncrRevKind { + fn for_revision_name(rev_name: &str) -> Result { + static MESSAGE: LazyLock = LazyLock::new(|| { + let values = IncrRevKind::STR_VARIANTS + .iter() + .map(|s| format!("`{s}`")) + .collect::>() + .join(", "); + format!("incremental revision name must begin with one of: {values}") + }); + + IncrRevKind::VARIANTS + .iter() + .copied() + .find(|kind| rev_name.starts_with(kind.to_str())) + .ok_or_else(|| MESSAGE.as_str()) + } +} impl TestCx<'_> { + /// Runs a single revision of an incremental test. pub(super) fn run_incremental_test(&self) { - // Basic plan for a test incremental/foo/bar.rs: - // - load list of revisions rpass1, bfail2, rpass3 - // - each should begin with `bfail`, `bpass`, or `rpass` - // - if `bfail`, expect compilation to fail - // - if `bpass`, expect compilation to succeed, don't execute - // - if `rpass`, expect compilation and execution to succeed - // - create a directory build/foo/bar.incremental - // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1 - // - because name of revision starts with "rpass", expect success - // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C bfail2 - // - because name of revision starts with "bfail", expect an error - // - load expected errors as usual, but filter for those with `[bfail2]` - // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass3 - // - because name of revision starts with "rpass", expect success - // - execute build/foo/bar.exe and save output - // - // FIXME -- use non-incremental mode as an oracle? That doesn't apply - // to #[rustc_clean] tests I guess - let revision = self.revision.expect("incremental tests require a list of revisions"); // Incremental workproduct directory should have already been created. @@ -31,68 +48,63 @@ impl TestCx<'_> { write!(self.stdout, "revision={:?} props={:#?}", revision, self.props); } - if revision.starts_with("cpass") { - self.run_cpass_test(); - } else if revision.starts_with("bpass") { - self.run_bpass_test(); - } else if revision.starts_with("rpass") { - self.run_rpass_test(); - } else if revision.starts_with("bfail") { - self.run_bfail_test(); - } else { - self.fatal("revision name must begin with `bfail`, `bpass`, or `rpass`"); + // Determine the revision kind from the revision name. + // The revision kind should be matched exhaustively to ensure that no cases are missed. + let rev_kind = IncrRevKind::for_revision_name(revision).unwrap_or_else(|e| self.fatal(e)); + + // Compile the test for this revision. + let emit = match rev_kind { + IncrRevKind::CheckPass => Emit::Metadata, // Do a check build. + IncrRevKind::BuildFail | IncrRevKind::BuildPass | IncrRevKind::RunPass => Emit::None, + }; + let will_execute = match rev_kind { + IncrRevKind::CheckPass | IncrRevKind::BuildFail | IncrRevKind::BuildPass => { + WillExecute::No + } + IncrRevKind::RunPass => { + // Yes, unless running test binaries is disabled. + self.run_if_enabled() + } + }; + let proc_res = &self.compile_test(will_execute, emit); + + // Check the compiler's exit status. + match rev_kind { + IncrRevKind::CheckPass | IncrRevKind::BuildPass | IncrRevKind::RunPass => { + // Compilation should have succeeded. + if !proc_res.status.success() { + self.fatal_proc_rec("test compilation failed although it shouldn't!", proc_res); + } + } + + IncrRevKind::BuildFail => { + // Compilation should have failed, with the expected status code. + if proc_res.status.success() { + self.fatal_proc_rec("incremental test did not emit an error", proc_res); + } + if !self.props.dont_check_failure_status { + self.check_correct_failure_status(proc_res); + } + } } - } - - fn run_cpass_test(&self) { - let proc_res = self.compile_test(WillExecute::No, Emit::Metadata); - self.check_if_test_should_compile(None, Some(PassMode::Check), &proc_res); - self.check_compiler_output_for_incr(&proc_res); - } - - fn run_bpass_test(&self) { - let emit_metadata = self.should_emit_metadata(self.pass_mode()); - let proc_res = self.compile_test(WillExecute::No, emit_metadata); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - self.check_compiler_output_for_incr(&proc_res); - } - - fn run_rpass_test(&self) { - let emit_metadata = self.should_emit_metadata(self.pass_mode()); - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, emit_metadata); - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - self.check_compiler_output_for_incr(&proc_res); - - if let WillExecute::Disabled = should_run { - return; - } - - let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } - - fn run_bfail_test(&self) { - let pm = self.pass_mode(); - let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); - self.check_if_test_should_compile(Some(FailMode::Build), pm, &proc_res); - self.check_compiler_output_for_incr(&proc_res); - } - - fn check_compiler_output_for_incr(&self, proc_res: &ProcRes) { + // Check compilation output. let output_to_check = self.get_output(proc_res); self.check_expected_errors(&proc_res); self.check_all_error_patterns(&output_to_check, proc_res); self.check_forbid_output(&output_to_check, proc_res); + + // Run the binary and check its exit status, if appropriate. + match rev_kind { + IncrRevKind::CheckPass | IncrRevKind::BuildFail | IncrRevKind::BuildPass => {} + IncrRevKind::RunPass => { + if self.config.run_enabled() { + let run_proc_res = self.exec_compiled_test(); + if !run_proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &run_proc_res); + } + } + } + } } } From 569ad9986443503f23c534d6c4d9f34e823f5c69 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Apr 2026 23:17:37 -0700 Subject: [PATCH 42/53] Only exclude the 155473 change for 1-byte bool-likes That's the thing we handle differently in codegen (see `to_immediate_scalar`) so if the other ones are fine, that helps narrow it down further. --- compiler/rustc_abi/src/lib.rs | 3 ++- tests/codegen-llvm/function-arguments.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b9414df2b86d7..22300fda5f698 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2084,7 +2084,8 @@ impl Niche { let distance_end_zero = max_value - v.end; // FIXME: this ought to work for `bool` too, but that seems to be hitting a miscompilation // - if count == 1 && v != (WrappingRange { start: 0, end: 1 }) { + let is_bool = size.bytes() == 1 && v == WrappingRange { start: 0, end: 1 }; + if count == 1 && !is_bool { // We only need one, so just pick the one closest to zero. // Not only does that obviously use zero if it's possible, but it also // simplifies testing things like `Option`, since looking for `-1` diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs index 80e6ac7bb0f03..87be219a2b2e0 100644 --- a/tests/codegen-llvm/function-arguments.rs +++ b/tests/codegen-llvm/function-arguments.rs @@ -297,7 +297,7 @@ pub fn return_slice(x: &[u16]) -> &[u16] { x } -// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 0, 3\))?}} %x.0, i16 %x.1) +// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 -1, 2\))?}} %x.0, i16 %x.1) #[no_mangle] pub fn enum_id_1(x: Option>) -> Option> { x From b7996bdc9a4e702c9e3b451f681bc9aa81a8bceb Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 24 Feb 2026 13:28:23 +0000 Subject: [PATCH 43/53] Existing code nits --- .../rustc_borrowck/src/handle_placeholders.rs | 18 +++++------ .../rustc_borrowck/src/region_infer/mod.rs | 31 +++++++++++-------- .../src/graph/scc/mod.rs | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index 2a7dc8ba10162..11b8890346dfb 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -35,18 +35,18 @@ pub(crate) struct LoweredConstraints<'tcx> { pub(crate) placeholder_indices: PlaceholderIndices<'tcx>, } -impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { - pub(crate) fn init(definitions: &'d IndexVec>) -> Self { - Self { scc_to_annotation: IndexVec::new(), definitions } - } -} - /// A Visitor for SCC annotation construction. pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { pub(crate) scc_to_annotation: IndexVec, definitions: &'d IndexVec>, } +impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { + pub(crate) fn init(definitions: &'d IndexVec>) -> Self { + Self { scc_to_annotation: IndexVec::new(), definitions } + } +} + impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { fn new(&self, element: RegionVid) -> RegionTracker { RegionTracker::new(element, &self.definitions[element]) @@ -118,7 +118,7 @@ impl RegionTracker { } /// The largest universe this SCC can name. It's the smallest - /// largest nameable universe of any reachable region, or + /// max-nameable-universe of any reachable region, or /// `max_nameable(r) = min (max_nameable(r') for r' reachable from r)` pub(crate) fn max_nameable_universe(self) -> UniverseIndex { self.max_nameable_universe.0 @@ -208,7 +208,7 @@ pub(super) fn region_definitions<'tcx>( /// graph such that there is a series of constraints /// A: B: C: ... : X where /// A contains a placeholder whose universe cannot be named by X, -/// add a constraint that A: 'static. This is a safe upper bound +/// add a constraint that X: 'static. This is a safe upper bound /// in the face of borrow checker/trait solver limitations that will /// eventually go away. /// @@ -327,8 +327,6 @@ pub(crate) fn rewrite_placeholder_outlives<'tcx>( for scc in sccs.all_sccs() { // No point in adding 'static: 'static! - // This micro-optimisation makes somewhat sense - // because static outlives *everything*. if scc == sccs.scc(fr_static) { continue; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 5cdda777723b3..2a759387788a7 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -501,43 +501,48 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut errors_buffer = RegionErrors::new(infcx.tcx); - // If this is a closure, we can propagate unsatisfied - // `outlives_requirements` to our creator, so create a vector - // to store those. Otherwise, we'll pass in `None` to the - // functions below, which will trigger them to report errors - // eagerly. - let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); + // If this is a nested body, we propagate unsatisfied + // outlives constraints to the parent body instead of + // eagerly erroing. + let mut propagated_outlives_requirements = + infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); - self.check_type_tests(infcx, outlives_requirements.as_mut(), &mut errors_buffer); + self.check_type_tests(infcx, propagated_outlives_requirements.as_mut(), &mut errors_buffer); debug!(?errors_buffer); - debug!(?outlives_requirements); + debug!(?propagated_outlives_requirements); // In Polonius mode, the errors about missing universal region relations are in the output // and need to be emitted or propagated. Otherwise, we need to check whether the // constraints were too strong, and if so, emit or propagate those errors. if infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() { self.check_polonius_subset_errors( - outlives_requirements.as_mut(), + propagated_outlives_requirements.as_mut(), &mut errors_buffer, polonius_output .as_ref() .expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { - self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); + self.check_universal_regions( + propagated_outlives_requirements.as_mut(), + &mut errors_buffer, + ); } debug!(?errors_buffer); - let outlives_requirements = outlives_requirements.unwrap_or_default(); + let propagated_outlives_requirements = propagated_outlives_requirements.unwrap_or_default(); - if outlives_requirements.is_empty() { + if propagated_outlives_requirements.is_empty() { (None, errors_buffer) } else { let num_external_vids = self.universal_regions().num_global_and_external_regions(); ( - Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), + Some(ClosureRegionRequirements { + num_external_vids, + outlives_requirements: propagated_outlives_requirements, + }), errors_buffer, ) } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 10abfd7a55ced..c04688e0a49fa 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -27,7 +27,7 @@ mod tests; /// the max/min element of the SCC, or all of the above. /// /// Concretely, the both merge operations must commute, e.g. where `merge` -/// is `update_scc` and `update_reached`: `a.merge(b) == b.merge(a)` +/// is `update_scc` and `update_reachable`: `a.merge(b) == b.merge(a)` /// /// In general, what you want is probably always min/max according /// to some ordering, potentially with side constraints (min x such From 2a8e588c9049da90b0aeb2d43b89e4186532ef22 Mon Sep 17 00:00:00 2001 From: "Eddy (Eduard) Stefes" Date: Thu, 23 Apr 2026 15:42:44 +0200 Subject: [PATCH 44/53] Add `--print=backend-has-mnemonic` and `needs-asm-mnemonic` directive Add infrastructure to query LLVM backend for specific assembly mnemonics and use it in compiletest to conditionally run tests based on instruction availability. This fixes test failures with naked-dead-code-elimination which requires the `RET` mnemonic. Co-authored-by: Folkert de Vries --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_llvm/src/llvm_util.rs | 11 ++++ compiler/rustc_driver_impl/src/lib.rs | 3 + .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 20 +++++++ .../rustc_session/src/config/print_request.rs | 37 ++++++++++-- .../rustc-dev-guide/src/tests/compiletest.md | 11 ++++ .../rustc-dev-guide/src/tests/directives.md | 3 + .../src/directives/directive_names.rs | 1 + src/tools/compiletest/src/directives/needs.rs | 60 +++++++++++++++++++ src/tools/compiletest/src/directives/tests.rs | 22 +++++++ .../naked-dead-code-elimination/rmake.rs | 1 + .../help-diff.diff | 2 +- .../unstable-invalid-print-request-help.err | 2 +- tests/run-make/rustc-help/help-v.stdout | 2 +- tests/run-make/rustc-help/help.stdout | 2 +- .../invalid/print-without-arg.stderr | 2 +- tests/ui/compile-flags/invalid/print.stderr | 2 +- .../ui/print-request/print-lints-help.stderr | 2 +- 18 files changed, 171 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 525d1dbe9d0d3..bed9242a3dbcf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2343,6 +2343,7 @@ unsafe extern "C" { pub(crate) fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString); pub(crate) fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; + pub(crate) fn LLVMRustTargetHasMnemonic(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString); pub(crate) fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 180559d28d848..e9983d11c127f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -480,6 +480,10 @@ pub(crate) fn print(req: &PrintRequest, out: &mut String, sess: &Session) { match req.kind { PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out), PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out), + PrintKind::BackendHasMnemonic => { + let mnemonic = req.arg.as_deref().expect("BackendHasMnemonic requires arg"); + print_target_has_mnemonic(tm.raw(), mnemonic, out) + } _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } @@ -738,3 +742,10 @@ pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> { let name = sess.opts.unstable_opts.tune_cpu.as_ref()?; Some(handle_native(name)) } + +fn print_target_has_mnemonic(tm: &llvm::TargetMachine, mnemonic: &str, out: &mut String) { + use std::fmt::Write; + let cstr = SmallCStr::new(mnemonic); + let has_mnemonic = unsafe { llvm::LLVMRustTargetHasMnemonic(tm, cstr.as_ptr()) }; + writeln!(out, "{}", has_mnemonic).unwrap(); +} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index c15c3c229398c..b05f5bc4a8e20 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -804,6 +804,9 @@ fn print_crate_info( let calling_conventions = rustc_abi::all_names(); println_info!("{}", calling_conventions.join("\n")); } + BackendHasMnemonic => { + codegen_backend.print(req, &mut crate_info, sess); + } BackendHasZstd => { let has_zstd: bool = codegen_backend.has_zstd(); println_info!("{has_zstd}"); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index b4f6bb4583c10..bad99f34567d9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -19,6 +19,7 @@ #include "llvm/IR/Verifier.h" #include "llvm/IRPrinter/IRPrintingPasses.h" #include "llvm/LTO/LTO.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/ObjectFile.h" @@ -94,6 +95,25 @@ extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, return MCInfo->checkFeatures(std::string("+") + Feature); } +/// Check whether the target has a specific assembly mnemonic like `ret` or +/// `nop`. +/// This should be fast enough but if its not we have to look into another +/// method of checking. +extern "C" bool LLVMRustTargetHasMnemonic(LLVMTargetMachineRef TM, + const char *Mnemonic) { + TargetMachine *Target = unwrap(TM); + const MCInstrInfo *MII = Target->getMCInstrInfo(); + StringRef MnemonicRef(Mnemonic); + + for (unsigned i = 0; i < MII->getNumOpcodes(); i++) { + StringRef Name = MII->getName(i); + if (Name.equals_insensitive(MnemonicRef)) { + return true; + } + } + return false; +} + enum class LLVMRustCodeModel { Tiny, Small, diff --git a/compiler/rustc_session/src/config/print_request.rs b/compiler/rustc_session/src/config/print_request.rs index dc53fcc6955f7..7c8ca4c0d3df3 100644 --- a/compiler/rustc_session/src/config/print_request.rs +++ b/compiler/rustc_session/src/config/print_request.rs @@ -15,6 +15,7 @@ use crate::macros::AllVariants; pub struct PrintRequest { pub kind: PrintKind, pub out: OutFileName, + pub arg: Option, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -22,6 +23,7 @@ pub struct PrintRequest { pub enum PrintKind { // tidy-alphabetical-start AllTargetSpecsJson, + BackendHasMnemonic, BackendHasZstd, CallingConventions, Cfg, @@ -60,6 +62,7 @@ impl PrintKind { match self { // tidy-alphabetical-start AllTargetSpecsJson => "all-target-specs-json", + BackendHasMnemonic => "backend-has-mnemonic", BackendHasZstd => "backend-has-zstd", CallingConventions => "calling-conventions", Cfg => "cfg", @@ -113,7 +116,8 @@ impl PrintKind { // Unstable values: AllTargetSpecsJson => false, - BackendHasZstd => false, // (perma-unstable, for use by compiletest) + BackendHasMnemonic => false, // (perma-unstable, for use by compiletest) + BackendHasZstd => false, // (perma-unstable, for use by compiletest) CheckCfg => false, CrateRootLintLevels => false, SupportedCrateTypes => false, @@ -150,11 +154,19 @@ pub(crate) fn collect_print_requests( ) -> Vec { let mut prints = Vec::::new(); if cg.target_cpu.as_deref() == Some("help") { - prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout }); + prints.push(PrintRequest { + kind: PrintKind::TargetCPUs, + out: OutFileName::Stdout, + arg: None, + }); cg.target_cpu = None; }; if cg.target_feature == "help" { - prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout }); + prints.push(PrintRequest { + kind: PrintKind::TargetFeatures, + out: OutFileName::Stdout, + arg: None, + }); cg.target_feature = String::new(); } @@ -167,9 +179,22 @@ pub(crate) fn collect_print_requests( prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); - let kind = if let Some(print_kind) = PrintKind::from_str(req) { + let (kind, arg) = if let Some(mnemonic) = req.strip_prefix("backend-has-mnemonic") { + check_print_request_stability(early_dcx, unstable_opts, PrintKind::BackendHasMnemonic); + // BackendHasMnemonic requires a mnemonic argument + if let Some(mnemonic) = mnemonic.strip_prefix(':') + && !mnemonic.is_empty() + { + (PrintKind::BackendHasMnemonic, Some(mnemonic.to_string())) + } else { + early_dcx.early_fatal( + "expected mnemonic name after `--print=backend-has-mnemonic:`, \ + for example: `--print=backend-has-mnemonic:RET`", + ); + } + } else if let Some(print_kind) = PrintKind::from_str(req) { check_print_request_stability(early_dcx, unstable_opts, print_kind); - print_kind + (print_kind, None) } else { let is_nightly = nightly_options::match_is_nightly_build(matches); emit_unknown_print_request_help(early_dcx, req, is_nightly) @@ -185,7 +210,7 @@ pub(crate) fn collect_print_requests( } } - PrintRequest { kind, out } + PrintRequest { kind, out, arg } })); prints diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 4c534e9ae0eda..53a6c0cb5737d 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -346,6 +346,17 @@ See also the [codegen tests](#codegen-tests) for a similar set of tests. If you need to work with `#![no_std]` cross-compiling tests, consult the [`minicore` test auxiliary](./minicore.md) chapter. +#### Conditional assembly tests based on instruction support + +Tests that depend on specific assembly instructions being available can use the +`//@ needs-asm-mnemonic: ` directive. This will skip the test if the +target backend does not support the specified instruction mnemonic. + +For example, a test that requires the `RET` instruction: +```rust,ignore +//@ needs-asm-mnemonic: RET +``` + [`tests/assembly-llvm`]: https://github.com/rust-lang/rust/tree/HEAD/tests/assembly-llvm diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 76bf2cdbea667..9498f7953ad04 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -163,6 +163,9 @@ The following directives will check rustc build settings and target settings: For tests that cross-compile to explicit targets via `--target`, use `needs-llvm-components` instead to ensure the appropriate backend is available. +- `needs-asm-mnemonic: ` — ignores if the target backend does not + support the specified assembly mnemonic (e.g., `RET`, `NOP`). + Only supported with the LLVM backend. - `needs-profiler-runtime` — ignores the test if the profiler runtime was not enabled for the target (`build.profiler = true` in `bootstrap.toml`) - `needs-sanitizer-support` — ignores if the sanitizer support was not enabled diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 34c6c1374b632..949c5ebfb29a7 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -156,6 +156,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "min-llvm-version", "min-system-llvm-version", "minicore-compile-flags", + "needs-asm-mnemonic", "needs-asm-support", "needs-backends", "needs-crate-type", diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index e9f3d6c28d6ef..88ca347edd0a5 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -290,6 +290,37 @@ pub(super) fn handle_needs( } } + if name == "needs-asm-mnemonic" { + let Some(rest) = ln.value_after_colon() else { + return IgnoreDecision::Error { + message: "expected `needs-asm-mnemonic` to have a mnemonic name after colon" + .to_string(), + }; + }; + + if !config.default_codegen_backend.is_llvm() { + return IgnoreDecision::Ignore { + reason: "skipping test as non-LLVM backend does not support mnemonic queries" + .to_string(), + }; + } + + let mnemonic = rest.trim(); + let has_mnemonic = match mnemonic { + "ret" => cache.has_ret_mnemonic, + "nop" => cache.has_nop_mnemonic, + _ => has_mnemonic(config, mnemonic), + }; + + if has_mnemonic { + return IgnoreDecision::Continue; + } else { + return IgnoreDecision::Ignore { + reason: format!("skipping test as target does not have `{mnemonic}` mnemonic"), + }; + } + } + if !name.starts_with("needs-") { return IgnoreDecision::Continue; } @@ -352,6 +383,10 @@ pub(super) struct CachedNeedsConditions { symlinks: bool, /// Whether LLVM built with zstd, for the `needs-llvm-zstd` directive. llvm_zstd: bool, + /// Might add particular other mnemonics heavily needed by tests here. + /// Otherwise call into llvm for every check + has_ret_mnemonic: bool, + has_nop_mnemonic: bool, } impl CachedNeedsConditions { @@ -399,6 +434,8 @@ impl CachedNeedsConditions { llvm_zstd: llvm_has_zstd(&config), dlltool: find_dlltool(&config), symlinks: has_symlinks(), + has_ret_mnemonic: has_mnemonic(config, "ret"), + has_nop_mnemonic: has_mnemonic(config, "nop"), } } } @@ -466,3 +503,26 @@ fn llvm_has_zstd(config: &Config) -> bool { _ => panic!("unexpected output from `--print=backend-has-zstd`: {output:?}"), } } + +fn has_mnemonic(config: &Config, mnemonic: &str) -> bool { + if !config.default_codegen_backend.is_llvm() { + return false; + } + + let target_flag = format!("--target={}", config.target); + let output = query_rustc_output( + config, + &[ + &target_flag, + "-Zunstable-options", + &format!("--print=backend-has-mnemonic:{}", mnemonic), + ], + Default::default(), + ); + + match output.trim() { + "true" => true, + "false" => false, + _ => panic!("unexpected output from `--print=backend-has-mnemonic:{mnemonic}`: {output:?}"), + } +} diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 4cd75fcfa511a..56d52982a8211 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -1254,3 +1254,25 @@ fn test_edition_range_edition_to_test() { assert_edition_to_test(2018, range, Some(e2024)); assert_edition_to_test(2018, range, Some(efuture)); } + +#[test] +fn needs_asm_mnemonic() { + let config_x86_64 = cfg().target("x86_64-unknown-linux-gnu").build(); + let config_aarch64 = cfg().target("aarch64-unknown-linux-gnu").build(); + + // invalid mnemonic + assert!(check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:GRUGGY")); + assert!(check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:gruggy")); + + // valid x86 and aarch64 + assert!(!check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:RET")); + assert!(!check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:ret")); + + // this is aarch64 specific + assert!(check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:ldrsbwui")); + assert!(!check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:LDRSBWui")); + + // this is x86 specific + assert!(check_ignore(&config_aarch64, "//@ needs-asm-mnemonic:CMPxCHG16B")); + assert!(!check_ignore(&config_x86_64, "//@ needs-asm-mnemonic:CMPXchg16B")); +} diff --git a/tests/run-make/naked-dead-code-elimination/rmake.rs b/tests/run-make/naked-dead-code-elimination/rmake.rs index 1be22de367c99..8e4c26fc34508 100644 --- a/tests/run-make/naked-dead-code-elimination/rmake.rs +++ b/tests/run-make/naked-dead-code-elimination/rmake.rs @@ -1,5 +1,6 @@ //@ ignore-cross-compile //@ needs-asm-support +//@ needs-asm-mnemonic: RET use run_make_support::symbols::object_contains_any_symbol; use run_make_support::{bin_name, rustc}; diff --git a/tests/run-make/print-request-help-stable-unstable/help-diff.diff b/tests/run-make/print-request-help-stable-unstable/help-diff.diff index e382a24782711..828a98d96b563 100644 --- a/tests/run-make/print-request-help-stable-unstable/help-diff.diff +++ b/tests/run-make/print-request-help-stable-unstable/help-diff.diff @@ -2,6 +2,6 @@ error: unknown print request: `xxx` | - = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models` -+ = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` ++ = help: valid print requests are: `all-target-specs-json`, `backend-has-mnemonic`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err index 70764ea13aa87..d0e4c81f1de9d 100644 --- a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err +++ b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err @@ -1,5 +1,5 @@ error: unknown print request: `xxx` | - = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `backend-has-mnemonic`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index 0acbb766c1556..1531f61089e9a 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -43,7 +43,7 @@ Options: --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - . + . -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o Write output to FILENAME diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 4075dd0282999..f96feccf35980 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -43,7 +43,7 @@ Options: --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - . + . -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o Write output to FILENAME diff --git a/tests/ui/compile-flags/invalid/print-without-arg.stderr b/tests/ui/compile-flags/invalid/print-without-arg.stderr index ff9669614360a..98788b4b87228 100644 --- a/tests/ui/compile-flags/invalid/print-without-arg.stderr +++ b/tests/ui/compile-flags/invalid/print-without-arg.stderr @@ -3,5 +3,5 @@ error: Argument to option 'print' missing --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - . + . diff --git a/tests/ui/compile-flags/invalid/print.stderr b/tests/ui/compile-flags/invalid/print.stderr index e2521ebf26a41..3eb7634d915db 100644 --- a/tests/ui/compile-flags/invalid/print.stderr +++ b/tests/ui/compile-flags/invalid/print.stderr @@ -1,5 +1,5 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `backend-has-mnemonic`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/print-request/print-lints-help.stderr b/tests/ui/print-request/print-lints-help.stderr index d39c6326e318b..c6e74e7dce7b6 100644 --- a/tests/ui/print-request/print-lints-help.stderr +++ b/tests/ui/print-request/print-lints-help.stderr @@ -1,6 +1,6 @@ error: unknown print request: `lints` | - = help: valid print requests are: `all-target-specs-json`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `backend-has-mnemonic`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: use `-Whelp` to print a list of lints = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information From 4d4058bfb43776e97bc71165b0e01fb008af6d6f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 28 Apr 2026 10:24:58 +0200 Subject: [PATCH 45/53] Add regression test for hkl const closures --- .../consts/const-closure-hkl.current.stderr | 17 +++++++++++++++ tests/ui/consts/const-closure-hkl.rs | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/ui/consts/const-closure-hkl.current.stderr create mode 100644 tests/ui/consts/const-closure-hkl.rs diff --git a/tests/ui/consts/const-closure-hkl.current.stderr b/tests/ui/consts/const-closure-hkl.current.stderr new file mode 100644 index 0000000000000..ac6b77901ae44 --- /dev/null +++ b/tests/ui/consts/const-closure-hkl.current.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `for<'a> {closure@$DIR/const-closure-hkl.rs:11:21: 11:48}: [const] FnOnce(&'a usize, &'a usize)` is not satisfied + --> $DIR/const-closure-hkl.rs:13:19 + | +LL | chaining_impl(len_chain); + | ------------- ^^^^^^^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `chaining_impl` + --> $DIR/const-closure-hkl.rs:17:32 + | +LL | const fn chaining_impl(x: impl for<'a> [const] FnOnce(&'a usize, &'a usize)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `chaining_impl` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-closure-hkl.rs b/tests/ui/consts/const-closure-hkl.rs new file mode 100644 index 0000000000000..62282ab91e832 --- /dev/null +++ b/tests/ui/consts/const-closure-hkl.rs @@ -0,0 +1,21 @@ +//! Regression test for hkl const closures not working in old solver + +//@[next] check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(const_trait_impl)] +#![feature(const_closures)] +const fn partial_compare() { + let len_chain = const move |_a: &_, _b: &_| {}; + + chaining_impl(len_chain); + //[current]~^ ERROR: [const] FnOnce(&'a usize, &'a usize)` is not satisfied +} + +const fn chaining_impl(x: impl for<'a> [const] FnOnce(&'a usize, &'a usize)) { + std::mem::forget(x); +} + +fn main() {} From b465c5642b4e0de570dfa24e2d40a347888a3a57 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 28 Apr 2026 10:31:16 +0200 Subject: [PATCH 46/53] Handle hkl const closures --- .../rustc_trait_selection/src/traits/effects.rs | 6 +----- .../ui/consts/const-closure-hkl.current.stderr | 17 ----------------- tests/ui/consts/const-closure-hkl.rs | 3 +-- 3 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 tests/ui/consts/const-closure-hkl.current.stderr diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index f0587b8e4e23e..0f36edcdd830e 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -554,11 +554,7 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( // but they don't really need to right now. ty::CoroutineClosure(_, _) => return Err(EvaluationFailure::NoSolution), - ty::Closure(def, args) => { - // For now we limit ourselves to closures without binders. The next solver can handle them. - args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?; - (def, args) - } + ty::Closure(def, args) => (def, args), // Everything else needs explicit impls or cannot have an impl _ => return Err(EvaluationFailure::NoSolution), diff --git a/tests/ui/consts/const-closure-hkl.current.stderr b/tests/ui/consts/const-closure-hkl.current.stderr deleted file mode 100644 index ac6b77901ae44..0000000000000 --- a/tests/ui/consts/const-closure-hkl.current.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `for<'a> {closure@$DIR/const-closure-hkl.rs:11:21: 11:48}: [const] FnOnce(&'a usize, &'a usize)` is not satisfied - --> $DIR/const-closure-hkl.rs:13:19 - | -LL | chaining_impl(len_chain); - | ------------- ^^^^^^^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `chaining_impl` - --> $DIR/const-closure-hkl.rs:17:32 - | -LL | const fn chaining_impl(x: impl for<'a> [const] FnOnce(&'a usize, &'a usize)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `chaining_impl` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-closure-hkl.rs b/tests/ui/consts/const-closure-hkl.rs index 62282ab91e832..25927b3a61ecd 100644 --- a/tests/ui/consts/const-closure-hkl.rs +++ b/tests/ui/consts/const-closure-hkl.rs @@ -1,6 +1,6 @@ //! Regression test for hkl const closures not working in old solver -//@[next] check-pass +//@ check-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver @@ -11,7 +11,6 @@ const fn partial_compare() { let len_chain = const move |_a: &_, _b: &_| {}; chaining_impl(len_chain); - //[current]~^ ERROR: [const] FnOnce(&'a usize, &'a usize)` is not satisfied } const fn chaining_impl(x: impl for<'a> [const] FnOnce(&'a usize, &'a usize)) { From 3b6080cb20924f0c4f94e47bbbbfcae8b07d82e5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:58:20 +0200 Subject: [PATCH 47/53] Rustup to rustc 1.97.0-nightly (52b6e2c20 2026-04-27) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 42db240bc4f86..486078185db84 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-04-20" +channel = "nightly-2026-04-28" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From 0eda44baacd49aff0b9bac6a00cdc56b6ad909db Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 28 Apr 2026 12:00:48 +0200 Subject: [PATCH 48/53] Delete the 12 year old fixme --- library/core/src/option.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index d4dd33b948193..02cd88a6a4340 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -40,9 +40,6 @@ //! } //! ``` //! -// -// FIXME: Show how `Option` is used in practice, with lots of methods -// //! # Options and pointers ("nullable" pointers) //! //! Rust's pointer types must always point to a valid location; there are From 62ee4cdaa427c4ff187d98f5d383c7da513b97c8 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Apr 2026 13:21:22 +0100 Subject: [PATCH 49/53] remove review queue triagebot mentions --- triagebot.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 9c69061c7b8cf..33ef3d097e618 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -940,10 +940,6 @@ Issue #{number} "{title}" has been added. # Mentions # ------------------------------------------------------------------------------ -[mentions."triagebot.toml"] -message = "`triagebot.toml` has been modified, there may have been changes to the review queue." -cc = ["@davidtwco", "@wesleywiser"] - [mentions."compiler/rustc_codegen_cranelift"] message = "The Cranelift subtree was changed" cc = ["@bjorn3"] From 81d67b7d030ac707d90616c40ce9a863df0a34c6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Apr 2026 16:35:01 +0200 Subject: [PATCH 50/53] Rename `SharedContext::emit_dyn_lint*` into `emit_lint*` --- .../rustc_attr_parsing/src/attributes/cfg.rs | 4 +- .../src/attributes/crate_level.rs | 2 +- .../attributes/diagnostic/do_not_recommend.rs | 4 +- .../src/attributes/diagnostic/mod.rs | 16 +++--- .../src/attributes/diagnostic/on_const.rs | 2 +- .../src/attributes/diagnostic/on_move.rs | 2 +- .../attributes/diagnostic/on_unimplemented.rs | 2 +- .../src/attributes/diagnostic/on_unknown.rs | 2 +- .../attributes/diagnostic/on_unmatch_args.rs | 2 +- .../rustc_attr_parsing/src/attributes/doc.rs | 50 +++++++++---------- .../src/attributes/proc_macro_attrs.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 12 ++--- .../rustc_attr_parsing/src/target_checking.rs | 4 +- 13 files changed, 52 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 84dd2b907aec8..cd86172e9476f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -224,7 +224,7 @@ pub(crate) fn parse_name_value( match cx.sess.psess.check_config.expecteds.get(&name) { Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx - .emit_dyn_lint_with_sess( + .emit_lint_with_sess( UNEXPECTED_CFGS, move |dcx, level, sess| { check_cfg::unexpected_cfg_value(sess, (name, name_span), value) @@ -232,7 +232,7 @@ pub(crate) fn parse_name_value( }, span, ), - None if cx.sess.psess.check_config.exhaustive_names => cx.emit_dyn_lint_with_sess( + None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint_with_sess( UNEXPECTED_CFGS, move |dcx, level, sess| { check_cfg::unexpected_cfg_name(sess, (name, name_span), value).into_diag(dcx, level) diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 451e126dd5c6a..f09cec67bd2e0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -67,7 +67,7 @@ impl CombineAttributeParser for CrateTypeParser { None, ); let span = n.value_span; - cx.emit_dyn_lint( + cx.emit_lint( UNKNOWN_CRATE_TYPES, move |dcx, level| { UnknownCrateTypes { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs index bf811438db93f..19dc7595a2ff1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs @@ -24,7 +24,7 @@ impl SingleAttributeParser for DoNotRecommendParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let attr_span = cx.attr_span; if !matches!(args, ArgParser::NoArgs) { - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, |dcx, level| crate::errors::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level), attr_span, @@ -33,7 +33,7 @@ impl SingleAttributeParser for DoNotRecommendParser { if !matches!(cx.target, Target::Impl { of_trait: true }) { let target_span = cx.target_span; - cx.emit_dyn_lint( + cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { IncorrectDoNotRecommendLocation { target_span }.into_diag(dcx, level) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 5f21d29035b01..5b5ed61e48d8a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -140,7 +140,7 @@ fn merge( (Some(_) | None, None) => {} (Some((first_span, _)), Some((later_span, _))) => { let first_span = *first_span; - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { IgnoredDiagnosticOption { first_span, later_span, option_name } @@ -167,14 +167,14 @@ fn parse_list<'p, S: Stage>( // We're dealing with `#[diagnostic::attr()]`. // This can be because that is what the user typed, but that's also what we'd see // if the user used non-metaitem syntax. See `ArgParser::from_attr_args`. - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| NonMetaItemDiagnosticAttribute.into_diag(dcx, level), list.span, ); } ArgParser::NoArgs => { - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { MissingOptionsForDiagnosticAttribute { @@ -187,7 +187,7 @@ fn parse_list<'p, S: Stage>( ); } ArgParser::NameValue(_) => { - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { MalFormedDiagnosticAttributeLint { @@ -221,7 +221,7 @@ fn parse_directive_items<'p, S: Stage>( let span = item.span(); macro malformed() {{ - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { MalFormedDiagnosticAttributeLint { @@ -249,7 +249,7 @@ fn parse_directive_items<'p, S: Stage>( macro duplicate($name: ident, $($first_span:tt)*) {{ let first_span = $($first_span)*; - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| IgnoredDiagnosticOption { first_span, @@ -285,7 +285,7 @@ fn parse_directive_items<'p, S: Stage>( | FormatWarning::PositionalArgument { span } | FormatWarning::IndexedArgument { span } | FormatWarning::DisallowedPlaceholder { span, .. }) = warning; - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, move |dcx, level| warning.into_diag(dcx, level), span, @@ -295,7 +295,7 @@ fn parse_directive_items<'p, S: Stage>( f } Err(e) => { - cx.emit_dyn_lint( + cx.emit_lint( MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, move |dcx, level| { WrappedParserError { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index 349b54706623b..3336242fc686a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -28,7 +28,7 @@ impl AttributeParser for OnConstParser { // so non-constness is still checked in check_attr.rs if !matches!(cx.target, Target::Impl { of_trait: true }) { let target_span = cx.target_span; - cx.emit_dyn_lint( + cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { DiagnosticOnConstOnlyForTraitImpls { target_span }.into_diag(dcx, level) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index feb48fa868d49..744281c15d8cb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -33,7 +33,7 @@ impl OnMoveParser { self.span = Some(span); if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) { - cx.emit_dyn_lint( + cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| DiagnosticOnMoveOnlyForAdt.into_diag(dcx, level), span, diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs index 069cda28582ec..910b9d9c70bec 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs @@ -23,7 +23,7 @@ impl OnUnimplementedParser { self.span = Some(span); if !matches!(cx.target, Target::Trait) { - cx.emit_dyn_lint( + cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| DiagnosticOnUnimplementedOnlyForTraits.into_diag(dcx, level), span, diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index d30ccfb73fe8b..b59ee678494a8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -35,7 +35,7 @@ impl OnUnknownParser { if !early && !matches!(cx.target, Target::Use) { let target_span = cx.target_span; - cx.emit_dyn_lint( + cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| { DiagnosticOnUnknownOnlyForImports { target_span }.into_diag(dcx, level) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs index f541f631bf12f..85f715e50c897 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs @@ -25,7 +25,7 @@ impl AttributeParser for OnUnmatchArgsParser { this.span = Some(span); if !matches!(cx.target, Target::MacroDef) { - cx.emit_dyn_lint( + cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, move |dcx, level| DiagnosticOnUnmatchArgsOnlyForMacros.into_diag(dcx, level), span, diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 60f469990d51a..9d2eeca644c8c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -68,7 +68,7 @@ fn check_attr_not_crate_level( /// Checks that an attribute is used at the crate level. Returns `true` if valid. fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool { if cx.shared.target != Target::Crate { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| AttrCrateLevelOnly.into_diag(dcx, level), span, @@ -84,7 +84,7 @@ fn expected_name_value( span: Span, _name: Option, ) { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| ExpectedNameValue.into_diag(dcx, level), span, @@ -93,7 +93,7 @@ fn expected_name_value( // FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead. fn expected_no_args(cx: &mut AcceptContext<'_, '_, S>, span: Span) { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| ExpectedNoArgs.into_diag(dcx, level), span, @@ -107,7 +107,7 @@ fn expected_string_literal( span: Span, _actual_literal: Option<&MetaItemLit>, ) { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| MalformedDoc.into_diag(dcx, level), span, @@ -177,7 +177,7 @@ impl DocParser { if let Some(used_span) = self.attribute.no_crate_inject { let unused_span = path.span(); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { rustc_errors::lints::UnusedDuplicate { @@ -203,7 +203,7 @@ impl DocParser { // FIXME: remove this method once merged and uncomment the line below instead. // cx.expected_list(cx.attr_span, args); let span = cx.attr_span; - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| MalformedDoc.into_diag(dcx, level), span, @@ -217,14 +217,14 @@ impl DocParser { } } Some(name) => { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| DocTestUnknown { name }.into_diag(dcx, level), path.span(), ); } None => { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| DocTestLiteral.into_diag(dcx, level), path.span(), @@ -261,7 +261,7 @@ impl DocParser { } if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, move |dcx, level| DocAliasDuplicated { first_definition }.into_diag(dcx, level), span, @@ -349,7 +349,7 @@ impl DocParser { ArgParser::List(list) => { for meta in list.mixed() { let MetaItemOrLitParser::MetaItemParser(item) = meta else { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level), meta.span(), @@ -360,7 +360,7 @@ impl DocParser { Some(sym::hide) => (HideOrShow::Hide, sym::hide), Some(sym::show) => (HideOrShow::Show, sym::show), _ => { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level), item.span(), @@ -369,7 +369,7 @@ impl DocParser { } }; let ArgParser::List(list) = item.args() else { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level) @@ -383,7 +383,7 @@ impl DocParser { for item in list.mixed() { let MetaItemOrLitParser::MetaItemParser(sub_item) = item else { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { DocAutoCfgHideShowUnexpectedItem { attr_name } @@ -399,7 +399,7 @@ impl DocParser { // FIXME: remove this method once merged and uncomment the line // below instead. // cx.expected_identifier(sub_item.path().span()); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| MalformedDoc.into_diag(dcx, level), sub_item.path().span(), @@ -426,7 +426,7 @@ impl DocParser { } } _ => { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { DocAutoCfgHideShowUnexpectedItem { attr_name } @@ -444,7 +444,7 @@ impl DocParser { ArgParser::NameValue(nv) => { let MetaItemLit { kind: LitKind::Bool(bool_value), span, .. } = nv.value_as_lit() else { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| DocAutoCfgWrongLiteral.into_diag(dcx, level), nv.value_span, @@ -588,7 +588,7 @@ impl DocParser { Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.as_list() else { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| DocTestTakesList.into_diag(dcx, level), args.span().unwrap_or(path.span()), @@ -605,7 +605,7 @@ impl DocParser { // FIXME: remove this method once merged and uncomment the line // below instead. // cx.unexpected_literal(lit.span); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| MalformedDoc.into_diag(dcx, level), lit.span, @@ -616,7 +616,7 @@ impl DocParser { } Some(sym::spotlight) => { let span = path.span(); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level), span, @@ -629,7 +629,7 @@ impl DocParser { }; let value = nv.value_as_lit().symbol; let span = path.span(); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { DocUnknownInclude { @@ -644,7 +644,7 @@ impl DocParser { } Some(name @ (sym::passes | sym::no_default_passes)) => { let span = path.span(); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { DocUnknownPasses { name, note_span: span }.into_diag(dcx, level) @@ -654,14 +654,14 @@ impl DocParser { } Some(sym::plugins) => { let span = path.span(); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| DocUnknownPlugins { label_span: span }.into_diag(dcx, level), span, ); } Some(name) => { - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| DocUnknownAny { name }.into_diag(dcx, level), path.span(), @@ -671,7 +671,7 @@ impl DocParser { let full_name = path.segments().map(|s| s.as_str()).intersperse("::").collect::(); let name = Symbol::intern(&full_name); - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| DocUnknownAny { name }.into_diag(dcx, level), path.span(), @@ -689,7 +689,7 @@ impl DocParser { ArgParser::NoArgs => { let suggestions = cx.adcx().suggestions(); let span = cx.attr_span; - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { IllFormedAttributeInput::new(&suggestions, None, None).into_diag(dcx, level) diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index e57a34e7888a7..5f7416cdbbf69 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -122,7 +122,7 @@ fn parse_derive_like( return None; } if rustc_feature::is_builtin_attr_name(ident.name) { - cx.emit_dyn_lint( + cx.emit_lint( AMBIGUOUS_DERIVE_HELPERS, |dcx, level| crate::errors::AmbiguousDeriveHelpers.into_diag(dcx, level), ident.span, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4058fdb7861fd..08fd785fb60b7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -462,7 +462,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing /// must be delayed until after HIR is built. This method will take care of the details of /// that. - pub(crate) fn emit_dyn_lint< + pub(crate) fn emit_lint< F: for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static, >( &mut self, @@ -477,7 +477,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { ); } - pub(crate) fn emit_dyn_lint_with_sess< + pub(crate) fn emit_lint_with_sess< F: for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()> + DynSend + DynSync @@ -507,7 +507,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { } pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { - self.emit_dyn_lint( + self.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, move |dcx, level| { rustc_errors::lints::UnusedDuplicate { @@ -526,7 +526,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { used_span: Span, unused_span: Span, ) { - self.emit_dyn_lint( + self.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, move |dcx, level| { rustc_errors::lints::UnusedDuplicate { @@ -951,7 +951,7 @@ where pub(crate) fn warn_empty_attribute(&mut self, span: Span) { let attr_path = self.attr_path.to_string(); let valid_without_list = self.template.word; - self.emit_dyn_lint( + self.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, move |dcx, level| { crate::errors::EmptyAttributeList { @@ -975,7 +975,7 @@ where ) { let suggestions = self.suggestions(); let span = self.attr_span; - self.emit_dyn_lint( + self.emit_lint( lint, move |dcx, level| { crate::errors::IllFormedAttributeInput::new(&suggestions, None, help.as_deref()) diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 8c41d7732c7d5..cf42e37152ab2 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -142,7 +142,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }; let attr_span = cx.attr_span; - cx.emit_dyn_lint( + cx.emit_lint( lint, move |dcx, level| { InvalidTargetLint { @@ -186,7 +186,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let target_span = cx.target_span; let attr_span = cx.attr_span; - cx.emit_dyn_lint( + cx.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, move |dcx, level| { crate::errors::InvalidAttrStyle { From 82ee1e04c63f893668962e5abc2696ea9b2ce00a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 12 Apr 2026 23:47:43 +0200 Subject: [PATCH 51/53] use larger ulps for `log` because it uses 2 inexact operations --- crates/std_float/tests/float.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/crates/std_float/tests/float.rs b/crates/std_float/tests/float.rs index 0fa5da3dca506..f97e1123c8527 100644 --- a/crates/std_float/tests/float.rs +++ b/crates/std_float/tests/float.rs @@ -33,23 +33,6 @@ macro_rules! unary_approx_test { } } -macro_rules! binary_approx_test { - { $scalar:tt, $($func:tt),+ } => { - test_helpers::test_lanes! { - $( - fn $func() { - test_helpers::test_binary_elementwise_approx( - &core_simd::simd::Simd::<$scalar, LANES>::$func, - &$scalar::$func, - &|_, _| true, - 16, - ) - } - )* - } - } -} - macro_rules! ternary_test { { $scalar:tt, $($func:tt),+ } => { test_helpers::test_lanes! { @@ -76,7 +59,19 @@ macro_rules! impl_tests { // https://github.com/rust-lang/miri/issues/3555 unary_approx_test! { $scalar, sin, cos, exp, exp2, ln, log2, log10 } - binary_approx_test! { $scalar, log } + + // The implementation of log is a.ln() / b.ln(), so there are 2 inexact operations, + // hence a larger ulps is needed. + test_helpers::test_lanes! { + fn log() { + test_helpers::test_binary_elementwise_approx( + &core_simd::simd::Simd::<$scalar, LANES>::log, + &$scalar::log, + &|_, _| true, + 32, + ) + } + } test_helpers::test_lanes! { fn fract() { From b1042604758be230eb352551451695ce923d3251 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 11 Apr 2026 20:33:22 +0200 Subject: [PATCH 52/53] bump toolchain to `nightly-2026-04-28` --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 6a58e59fb93ef..27d2dd6efbbb8 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-03-18" +channel = "nightly-2026-04-28" components = ["rustfmt", "clippy", "miri", "rust-src"] From aef93ca43af9464ce2efb8678df70444770c2c70 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 28 Apr 2026 15:16:49 +0000 Subject: [PATCH 53/53] Document that CFI diverges from Rust wrt. ABI-compatibility rules --- library/core/src/primitive_docs.rs | 5 ++- .../src/compiler-flags/sanitizer.md | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 3a4e1e657a3da..48bf57356b575 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1794,6 +1794,7 @@ mod prim_ref {} /// have different sizes. /// /// ### ABI compatibility +/// [ABI compatibility]: #abi-compatibility /// /// Generally, when a function is declared with one signature and called via a function pointer with /// a different signature, the two signatures must be *ABI-compatible* or else calling the function @@ -1831,7 +1832,7 @@ mod prim_ref {} /// - `*const T`, `*mut T`, `&T`, `&mut T`, `Box` (specifically, only `Box`), and /// `NonNull` are all ABI-compatible with each other for all `T`. They are also ABI-compatible /// with each other for _different_ `T` if they have the same metadata type (`::Metadata`). +/// Pointee>::Metadata`). However, see the [Control Flow Integrity][cfi-docs] docs for caveats. /// - `usize` is ABI-compatible with the `uN` integer type of the same size, and likewise `isize` is /// ABI-compatible with the `iN` integer type of the same size. /// - `char` is ABI-compatible with `u32`. @@ -1890,6 +1891,8 @@ mod prim_ref {} /// Behavior since transmuting `None::>` to `NonZero` violates the non-zero /// requirement. /// +/// [cfi-docs]: https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity +/// /// ### Trait implementations /// /// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index b0f6c97ff5a73..5bd518b14154b 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -246,6 +246,37 @@ Cargo build-std feature (i.e., `-Zbuild-std`) when enabling CFI. See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. +## Divergence from the Rust ABI + +There are some caveats to [the ABI-compatibility rules for Rust-to-Rust +calls][rust-abi] due to how the CFI sanitizer is implemented. CFI is a tool +that can be used to validate that dynamic function calls respect the ABI, but +due to its C/C++ origins, it disagrees with the above documented guarantees in +a few ways, see below. As CFI is unstable, the details may change in the +future. + +When running the CFI sanitizer, pointer types are only ABI-compatible if the +target type and mutability is the same. This means that `*mut String` and `*mut +i32` are incompatible when using CFI. It also means that `*mut i32` is +incompatible with `*const i32`. The `NonNull<_>` and `Box<_>` pointer types are +currently considered immutable under CFI. For non-primitive target types, CFI +uses the name of the type for its compatibility check. + +When not using the `-Zsanitizer-cfi-normalize-integers` flag, the CFI sanitizer +further restricts the rules by considering `usize`/`isize` incompatible with +the `uN`/`iN` integer type of the same size. + +Unlike other cases where the function ABI is violated, function calls that +violate the CFI-specific ABI-compatibility rules are not undefined behavior. +They are guaranteed to either function correctly, or to crash the program. + +This section only covers cases where CFI disagrees with the ABI-compatibility +rules for Rust-to-Rust calls. It is not meant to be a complete explanation of +how CFI works, and details important for C-to-Rust or Rust-to-C calls are +omitted. + +[rust-abi]: https://doc.rust-lang.org/stable/std/primitive.fn.html#abi-compatibility + ## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination ```rust