From 5b2de8ab27e4a319e23817b61830a5cc6fd1745e Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 09:26:12 +0200 Subject: Move `std_detect` from `library/stdarch` to `library` --- library/std_detect/Cargo.toml | 41 ++ library/std_detect/LICENSE-APACHE | 201 +++++++++ library/std_detect/LICENSE-MIT | 25 ++ library/std_detect/README.md | 93 ++++ library/std_detect/src/detect/arch/aarch64.rs | 259 +++++++++++ library/std_detect/src/detect/arch/arm.rs | 29 ++ library/std_detect/src/detect/arch/loongarch.rs | 51 +++ library/std_detect/src/detect/arch/mips.rs | 12 + library/std_detect/src/detect/arch/mips64.rs | 12 + library/std_detect/src/detect/arch/mod.rs | 75 ++++ library/std_detect/src/detect/arch/powerpc.rs | 30 ++ library/std_detect/src/detect/arch/powerpc64.rs | 30 ++ library/std_detect/src/detect/arch/riscv.rs | 344 +++++++++++++++ library/std_detect/src/detect/arch/s390x.rs | 81 ++++ library/std_detect/src/detect/arch/x86.rs | 278 ++++++++++++ library/std_detect/src/detect/bit.rs | 9 + library/std_detect/src/detect/cache.rs | 223 ++++++++++ library/std_detect/src/detect/macros.rs | 204 +++++++++ library/std_detect/src/detect/mod.rs | 121 ++++++ library/std_detect/src/detect/os/aarch64.rs | 130 ++++++ library/std_detect/src/detect/os/darwin/aarch64.rs | 155 +++++++ .../std_detect/src/detect/os/freebsd/aarch64.rs | 3 + library/std_detect/src/detect/os/freebsd/arm.rs | 36 ++ library/std_detect/src/detect/os/freebsd/auxvec.rs | 66 +++ library/std_detect/src/detect/os/freebsd/mod.rs | 22 + .../std_detect/src/detect/os/freebsd/powerpc.rs | 21 + library/std_detect/src/detect/os/linux/aarch64.rs | 484 +++++++++++++++++++++ library/std_detect/src/detect/os/linux/arm.rs | 34 ++ library/std_detect/src/detect/os/linux/auxvec.rs | 341 +++++++++++++++ .../std_detect/src/detect/os/linux/loongarch.rs | 68 +++ library/std_detect/src/detect/os/linux/mips.rs | 23 + library/std_detect/src/detect/os/linux/mod.rs | 67 +++ library/std_detect/src/detect/os/linux/powerpc.rs | 35 ++ library/std_detect/src/detect/os/linux/riscv.rs | 330 ++++++++++++++ library/std_detect/src/detect/os/linux/s390x.rs | 152 +++++++ .../std_detect/src/detect/os/openbsd/aarch64.rs | 55 +++ library/std_detect/src/detect/os/other.rs | 8 + library/std_detect/src/detect/os/riscv.rs | 203 +++++++++ .../std_detect/src/detect/os/windows/aarch64.rs | 125 ++++++ library/std_detect/src/detect/os/x86.rs | 335 ++++++++++++++ .../detect/test_data/linux-artificial-aarch64.auxv | Bin 0 -> 336 bytes .../test_data/linux-empty-hwcap2-aarch64.auxv | Bin 0 -> 336 bytes .../src/detect/test_data/linux-hwcap2-aarch64.auxv | Bin 0 -> 336 bytes .../detect/test_data/linux-no-hwcap2-aarch64.auxv | Bin 0 -> 320 bytes .../src/detect/test_data/linux-rpi3.auxv | Bin 0 -> 160 bytes .../macos-virtualbox-linux-x86-4850HQ.auxv | Bin 0 -> 160 bytes library/std_detect/src/lib.rs | 36 ++ library/std_detect/tests/cpu-detection.rs | 354 +++++++++++++++ library/std_detect/tests/macro_trailing_commas.rs | 109 +++++ library/std_detect/tests/x86-specific.rs | 117 +++++ library/stdarch/crates/std_detect/Cargo.toml | 41 -- library/stdarch/crates/std_detect/LICENSE-APACHE | 201 --------- library/stdarch/crates/std_detect/LICENSE-MIT | 25 -- library/stdarch/crates/std_detect/README.md | 93 ---- .../crates/std_detect/src/detect/arch/aarch64.rs | 259 ----------- .../crates/std_detect/src/detect/arch/arm.rs | 29 -- .../crates/std_detect/src/detect/arch/loongarch.rs | 51 --- .../crates/std_detect/src/detect/arch/mips.rs | 12 - .../crates/std_detect/src/detect/arch/mips64.rs | 12 - .../crates/std_detect/src/detect/arch/mod.rs | 75 ---- .../crates/std_detect/src/detect/arch/powerpc.rs | 30 -- .../crates/std_detect/src/detect/arch/powerpc64.rs | 30 -- .../crates/std_detect/src/detect/arch/riscv.rs | 344 --------------- .../crates/std_detect/src/detect/arch/s390x.rs | 81 ---- .../crates/std_detect/src/detect/arch/x86.rs | 278 ------------ .../stdarch/crates/std_detect/src/detect/bit.rs | 9 - .../stdarch/crates/std_detect/src/detect/cache.rs | 223 ---------- .../stdarch/crates/std_detect/src/detect/macros.rs | 204 --------- .../stdarch/crates/std_detect/src/detect/mod.rs | 121 ------ .../crates/std_detect/src/detect/os/aarch64.rs | 130 ------ .../std_detect/src/detect/os/darwin/aarch64.rs | 155 ------- .../std_detect/src/detect/os/freebsd/aarch64.rs | 3 - .../crates/std_detect/src/detect/os/freebsd/arm.rs | 36 -- .../std_detect/src/detect/os/freebsd/auxvec.rs | 66 --- .../crates/std_detect/src/detect/os/freebsd/mod.rs | 22 - .../std_detect/src/detect/os/freebsd/powerpc.rs | 21 - .../std_detect/src/detect/os/linux/aarch64.rs | 484 --------------------- .../crates/std_detect/src/detect/os/linux/arm.rs | 34 -- .../std_detect/src/detect/os/linux/auxvec.rs | 341 --------------- .../std_detect/src/detect/os/linux/loongarch.rs | 68 --- .../crates/std_detect/src/detect/os/linux/mips.rs | 23 - .../crates/std_detect/src/detect/os/linux/mod.rs | 67 --- .../std_detect/src/detect/os/linux/powerpc.rs | 35 -- .../crates/std_detect/src/detect/os/linux/riscv.rs | 330 -------------- .../crates/std_detect/src/detect/os/linux/s390x.rs | 152 ------- .../std_detect/src/detect/os/openbsd/aarch64.rs | 55 --- .../crates/std_detect/src/detect/os/other.rs | 8 - .../crates/std_detect/src/detect/os/riscv.rs | 203 --------- .../std_detect/src/detect/os/windows/aarch64.rs | 125 ------ .../stdarch/crates/std_detect/src/detect/os/x86.rs | 335 -------------- .../detect/test_data/linux-artificial-aarch64.auxv | Bin 336 -> 0 bytes .../test_data/linux-empty-hwcap2-aarch64.auxv | Bin 336 -> 0 bytes .../src/detect/test_data/linux-hwcap2-aarch64.auxv | Bin 336 -> 0 bytes .../detect/test_data/linux-no-hwcap2-aarch64.auxv | Bin 320 -> 0 bytes .../src/detect/test_data/linux-rpi3.auxv | Bin 160 -> 0 bytes .../macos-virtualbox-linux-x86-4850HQ.auxv | Bin 160 -> 0 bytes library/stdarch/crates/std_detect/src/lib.rs | 36 -- .../crates/std_detect/tests/cpu-detection.rs | 354 --------------- .../std_detect/tests/macro_trailing_commas.rs | 109 ----- .../crates/std_detect/tests/x86-specific.rs | 117 ----- 100 files changed, 5427 insertions(+), 5427 deletions(-) create mode 100644 library/std_detect/Cargo.toml create mode 100644 library/std_detect/LICENSE-APACHE create mode 100644 library/std_detect/LICENSE-MIT create mode 100644 library/std_detect/README.md create mode 100644 library/std_detect/src/detect/arch/aarch64.rs create mode 100644 library/std_detect/src/detect/arch/arm.rs create mode 100644 library/std_detect/src/detect/arch/loongarch.rs create mode 100644 library/std_detect/src/detect/arch/mips.rs create mode 100644 library/std_detect/src/detect/arch/mips64.rs create mode 100644 library/std_detect/src/detect/arch/mod.rs create mode 100644 library/std_detect/src/detect/arch/powerpc.rs create mode 100644 library/std_detect/src/detect/arch/powerpc64.rs create mode 100644 library/std_detect/src/detect/arch/riscv.rs create mode 100644 library/std_detect/src/detect/arch/s390x.rs create mode 100644 library/std_detect/src/detect/arch/x86.rs create mode 100644 library/std_detect/src/detect/bit.rs create mode 100644 library/std_detect/src/detect/cache.rs create mode 100644 library/std_detect/src/detect/macros.rs create mode 100644 library/std_detect/src/detect/mod.rs create mode 100644 library/std_detect/src/detect/os/aarch64.rs create mode 100644 library/std_detect/src/detect/os/darwin/aarch64.rs create mode 100644 library/std_detect/src/detect/os/freebsd/aarch64.rs create mode 100644 library/std_detect/src/detect/os/freebsd/arm.rs create mode 100644 library/std_detect/src/detect/os/freebsd/auxvec.rs create mode 100644 library/std_detect/src/detect/os/freebsd/mod.rs create mode 100644 library/std_detect/src/detect/os/freebsd/powerpc.rs create mode 100644 library/std_detect/src/detect/os/linux/aarch64.rs create mode 100644 library/std_detect/src/detect/os/linux/arm.rs create mode 100644 library/std_detect/src/detect/os/linux/auxvec.rs create mode 100644 library/std_detect/src/detect/os/linux/loongarch.rs create mode 100644 library/std_detect/src/detect/os/linux/mips.rs create mode 100644 library/std_detect/src/detect/os/linux/mod.rs create mode 100644 library/std_detect/src/detect/os/linux/powerpc.rs create mode 100644 library/std_detect/src/detect/os/linux/riscv.rs create mode 100644 library/std_detect/src/detect/os/linux/s390x.rs create mode 100644 library/std_detect/src/detect/os/openbsd/aarch64.rs create mode 100644 library/std_detect/src/detect/os/other.rs create mode 100644 library/std_detect/src/detect/os/riscv.rs create mode 100644 library/std_detect/src/detect/os/windows/aarch64.rs create mode 100644 library/std_detect/src/detect/os/x86.rs create mode 100644 library/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv create mode 100644 library/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv create mode 100644 library/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv create mode 100644 library/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv create mode 100644 library/std_detect/src/detect/test_data/linux-rpi3.auxv create mode 100644 library/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv create mode 100644 library/std_detect/src/lib.rs create mode 100644 library/std_detect/tests/cpu-detection.rs create mode 100644 library/std_detect/tests/macro_trailing_commas.rs create mode 100644 library/std_detect/tests/x86-specific.rs delete mode 100644 library/stdarch/crates/std_detect/Cargo.toml delete mode 100644 library/stdarch/crates/std_detect/LICENSE-APACHE delete mode 100644 library/stdarch/crates/std_detect/LICENSE-MIT delete mode 100644 library/stdarch/crates/std_detect/README.md delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/arm.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/loongarch.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/mips.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/mips64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/mod.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/riscv.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/s390x.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/arch/x86.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/bit.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/cache.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/macros.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/mod.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/darwin/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/arm.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/loongarch.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/mips.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/powerpc.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/riscv.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/other.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/riscv.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/windows/aarch64.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/os/x86.rs delete mode 100644 library/stdarch/crates/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv delete mode 100644 library/stdarch/crates/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv delete mode 100644 library/stdarch/crates/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv delete mode 100644 library/stdarch/crates/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv delete mode 100644 library/stdarch/crates/std_detect/src/detect/test_data/linux-rpi3.auxv delete mode 100644 library/stdarch/crates/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv delete mode 100644 library/stdarch/crates/std_detect/src/lib.rs delete mode 100644 library/stdarch/crates/std_detect/tests/cpu-detection.rs delete mode 100644 library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs delete mode 100644 library/stdarch/crates/std_detect/tests/x86-specific.rs diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml new file mode 100644 index 00000000000..f990e724125 --- /dev/null +++ b/library/std_detect/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "std_detect" +version = "0.1.5" +authors = [ + "Alex Crichton ", + "Andrew Gallant ", + "Gonzalo Brito Gadeschi ", +] +description = "`std::detect` - Rust's standard library run-time CPU feature detection." +homepage = "https://github.com/rust-lang/stdarch" +repository = "https://github.com/rust-lang/stdarch" +readme = "README.md" +keywords = ["std", "run-time", "feature", "detection"] +categories = ["hardware-support"] +license = "MIT OR Apache-2.0" +edition = "2024" + +[badges] +is-it-maintained-issue-resolution = { repository = "rust-lang/stdarch" } +is-it-maintained-open-issues = { repository = "rust-lang/stdarch" } +maintenance = { status = "experimental" } + +[dependencies] +cfg-if = "1.0.0" + +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + +[target.'cfg(not(windows))'.dependencies] +libc = { version = "0.2.0", optional = true, default-features = false } + +[features] +default = [ "std_detect_dlsym_getauxval", "std_detect_file_io" ] +std_detect_file_io = [ "libc" ] +std_detect_dlsym_getauxval = [ "libc" ] +std_detect_env_override = [ "libc" ] +rustc-dep-of-std = [ + "core", + "alloc", +] diff --git a/library/std_detect/LICENSE-APACHE b/library/std_detect/LICENSE-APACHE new file mode 100644 index 00000000000..16fe87b06e8 --- /dev/null +++ b/library/std_detect/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/library/std_detect/LICENSE-MIT b/library/std_detect/LICENSE-MIT new file mode 100644 index 00000000000..52d82415d8b --- /dev/null +++ b/library/std_detect/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/library/std_detect/README.md b/library/std_detect/README.md new file mode 100644 index 00000000000..edc90d319a1 --- /dev/null +++ b/library/std_detect/README.md @@ -0,0 +1,93 @@ +`std::detect` - Rust's standard library run-time CPU feature detection +======= + +The private `std::detect` module implements run-time feature detection in Rust's +standard library. This allows detecting whether the CPU the binary runs on +supports certain features, like SIMD instructions. + +# Usage + +`std::detect` APIs are available as part of `libstd`. Prefer using it via the +standard library than through this crate. Unstable features of `std::detect` are +available on nightly Rust behind various feature-gates. + +If you need run-time feature detection in `#[no_std]` environments, Rust `core` +library cannot help you. By design, Rust `core` is platform independent, but +performing run-time feature detection requires a certain level of cooperation +from the platform. + +You can then manually include `std_detect` as a dependency to get similar +run-time feature detection support than the one offered by Rust's standard +library. We intend to make `std_detect` more flexible and configurable in this +regard to better serve the needs of `#[no_std]` targets. + +# Features + +* `std_detect_dlsym_getauxval` (enabled by default, requires `libc`): Enable to +use `libc::dlsym` to query whether [`getauxval`] is linked into the binary. When +this is not the case, this feature allows other fallback methods to perform +run-time feature detection. When this feature is disabled, `std_detect` assumes +that [`getauxval`] is linked to the binary. If that is not the case the behavior +is undefined. + + Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets + because we can safely assume `getauxval` is linked to the binary. + * `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) + have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). + * `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) + use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) + * `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) + * `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) + have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). + +* `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature +detection using file APIs (e.g. `/proc/self/auxv`, etc.) if other more performant +methods fail. This feature requires `libstd` as a dependency, preventing the +crate from working on applications in which `std` is not available. + +[`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html + +# Platform support + +* All `x86`/`x86_64` targets are supported on all platforms by querying the + `cpuid` instruction directly for the features supported by the hardware and + the operating system. `std_detect` assumes that the binary is an user-space + application. + +* Linux/Android: + * `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `loongarch{32,64}`, `s390x`: + `std_detect` supports these on Linux by querying ELF auxiliary vectors (using `getauxval` + when available), and if that fails, by querying `/proc/self/auxv`. + * `arm64`: partial support for doing run-time feature detection by directly + querying `mrs` is implemented for Linux >= 4.11, but not enabled by default. + * `riscv{32,64}`: + `std_detect` supports these on Linux by querying `riscv_hwprobe`, and + by querying ELF auxiliary vectors (using `getauxval` when available). + +* FreeBSD: + * `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF + auxiliary vectors using `sysctl`. + * `arm64`: run-time feature detection is implemented by directly querying `mrs`. + +* OpenBSD: + * `arm64`: run-time feature detection is implemented by querying `sysctl`. + +* Windows: + * `arm64`: run-time feature detection is implemented by querying `IsProcessorFeaturePresent`. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `std_detect` by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/library/std_detect/src/detect/arch/aarch64.rs b/library/std_detect/src/detect/arch/aarch64.rs new file mode 100644 index 00000000000..13570a25c1c --- /dev/null +++ b/library/std_detect/src/detect/arch/aarch64.rs @@ -0,0 +1,259 @@ +//! Aarch64 run-time features. + +features! { + @TARGET: aarch64; + @CFG: any(target_arch = "aarch64", target_arch = "arm64ec"); + @MACRO_NAME: is_aarch64_feature_detected; + @MACRO_ATTRS: + /// This macro tests, at runtime, whether an `aarch64` feature is enabled on aarch64 platforms. + /// Currently most features are only supported on linux-based platforms. + /// + /// This macro takes one argument which is a string literal of the feature being tested for. + /// The feature names are mostly taken from their FEAT_* definitions in the [ARM Architecture + /// Reference Manual][docs]. + /// + /// ## Supported arguments + /// + /// * `"aes"` - FEAT_AES & FEAT_PMULL + /// * `"asimd"` or "neon" - FEAT_AdvSIMD + /// * `"bf16"` - FEAT_BF16 + /// * `"bti"` - FEAT_BTI + /// * `"crc"` - FEAT_CRC + /// * `"cssc"` - FEAT_CSSC + /// * `"dit"` - FEAT_DIT + /// * `"dotprod"` - FEAT_DotProd + /// * `"dpb"` - FEAT_DPB + /// * `"dpb2"` - FEAT_DPB2 + /// * `"ecv"` - FEAT_ECV + /// * `"f32mm"` - FEAT_F32MM + /// * `"f64mm"` - FEAT_F64MM + /// * `"faminmax"` - FEAT_FAMINMAX + /// * `"fcma"` - FEAT_FCMA + /// * `"fhm"` - FEAT_FHM + /// * `"flagm"` - FEAT_FLAGM + /// * `"flagm2"` - FEAT_FLAGM2 + /// * `"fp"` - FEAT_FP + /// * `"fp16"` - FEAT_FP16 + /// * `"fp8"` - FEAT_FP8 + /// * `"fp8dot2"` - FEAT_FP8DOT2 + /// * `"fp8dot4"` - FEAT_FP8DOT4 + /// * `"fp8fma"` - FEAT_FP8FMA + /// * `"fpmr"` - FEAT_FPMR + /// * `"frintts"` - FEAT_FRINTTS + /// * `"hbc"` - FEAT_HBC + /// * `"i8mm"` - FEAT_I8MM + /// * `"jsconv"` - FEAT_JSCVT + /// * `"lse"` - FEAT_LSE + /// * `"lse128"` - FEAT_LSE128 + /// * `"lse2"` - FEAT_LSE2 + /// * `"lut"` - FEAT_LUT + /// * `"mops"` - FEAT_MOPS + /// * `"mte"` - FEAT_MTE & FEAT_MTE2 + /// * `"paca"` - FEAT_PAuth (address authentication) + /// * `"pacg"` - FEAT_Pauth (generic authentication) + /// * `"pauth-lr"` - FEAT_PAuth_LR + /// * `"pmull"` - FEAT_PMULL + /// * `"rand"` - FEAT_RNG + /// * `"rcpc"` - FEAT_LRCPC + /// * `"rcpc2"` - FEAT_LRCPC2 + /// * `"rcpc3"` - FEAT_LRCPC3 + /// * `"rdm"` - FEAT_RDM + /// * `"sb"` - FEAT_SB + /// * `"sha2"` - FEAT_SHA1 & FEAT_SHA256 + /// * `"sha3"` - FEAT_SHA512 & FEAT_SHA3 + /// * `"sm4"` - FEAT_SM3 & FEAT_SM4 + /// * `"sme"` - FEAT_SME + /// * `"sme-b16b16"` - FEAT_SME_B16B16 + /// * `"sme-f16f16"` - FEAT_SME_F16F16 + /// * `"sme-f64f64"` - FEAT_SME_F64F64 + /// * `"sme-f8f16"` - FEAT_SME_F8F16 + /// * `"sme-f8f32"` - FEAT_SME_F8F32 + /// * `"sme-fa64"` - FEAT_SME_FA64 + /// * `"sme-i16i64"` - FEAT_SME_I16I64 + /// * `"sme-lutv2"` - FEAT_SME_LUTv2 + /// * `"sme2"` - FEAT_SME2 + /// * `"sme2p1"` - FEAT_SME2p1 + /// * `"ssbs"` - FEAT_SSBS & FEAT_SSBS2 + /// * `"ssve-fp8dot2"` - FEAT_SSVE_FP8DOT2 + /// * `"ssve-fp8dot4"` - FEAT_SSVE_FP8DOT4 + /// * `"ssve-fp8fma"` - FEAT_SSVE_FP8FMA + /// * `"sve"` - FEAT_SVE + /// * `"sve-b16b16"` - FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) + /// * `"sve2"` - FEAT_SVE2 + /// * `"sve2-aes"` - FEAT_SVE_AES & FEAT_SVE_PMULL128 (SVE2 AES crypto) + /// * `"sve2-bitperm"` - FEAT_SVE2_BitPerm + /// * `"sve2-sha3"` - FEAT_SVE2_SHA3 + /// * `"sve2-sm4"` - FEAT_SVE2_SM4 + /// * `"sve2p1"` - FEAT_SVE2p1 + /// * `"tme"` - FEAT_TME + /// * `"wfxt"` - FEAT_WFxT + /// + /// [docs]: https://developer.arm.com/documentation/ddi0487/latest + #[stable(feature = "simd_aarch64", since = "1.60.0")] + @BIND_FEATURE_NAME: "asimd"; "neon"; + @NO_RUNTIME_DETECTION: "ras"; + @NO_RUNTIME_DETECTION: "v8.1a"; + @NO_RUNTIME_DETECTION: "v8.2a"; + @NO_RUNTIME_DETECTION: "v8.3a"; + @NO_RUNTIME_DETECTION: "v8.4a"; + @NO_RUNTIME_DETECTION: "v8.5a"; + @NO_RUNTIME_DETECTION: "v8.6a"; + @NO_RUNTIME_DETECTION: "v8.7a"; + @NO_RUNTIME_DETECTION: "v8.8a"; + @NO_RUNTIME_DETECTION: "v8.9a"; + @NO_RUNTIME_DETECTION: "v9.1a"; + @NO_RUNTIME_DETECTION: "v9.2a"; + @NO_RUNTIME_DETECTION: "v9.3a"; + @NO_RUNTIME_DETECTION: "v9.4a"; + @NO_RUNTIME_DETECTION: "v9.5a"; + @NO_RUNTIME_DETECTION: "v9a"; + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] asimd: "neon"; + /// FEAT_AdvSIMD (Advanced SIMD/NEON) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pmull: "pmull"; + implied by target_features: ["aes"]; + /// FEAT_PMULL (Polynomial Multiply) - Implied by `aes` target_feature + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp: "fp"; + implied by target_features: ["neon"]; + /// FEAT_FP (Floating point support) - Implied by `neon` target_feature + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] aes: "aes"; + /// FEAT_AES (AES SIMD instructions) & FEAT_PMULL (PMULL{2}, 64-bit operand variants) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] bf16: "bf16"; + /// FEAT_BF16 (BFloat16 type, plus MM instructions, plus ASIMD support) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] bti: "bti"; + /// FEAT_BTI (Branch Target Identification) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] crc: "crc"; + /// FEAT_CRC32 (Cyclic Redundancy Check) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] cssc: "cssc"; + /// FEAT_CSSC (Common Short Sequence Compression instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dit: "dit"; + /// FEAT_DIT (Data Independent Timing instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dpb: "dpb"; + /// FEAT_DPB (aka dcpop - data cache clean to point of persistence) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dpb2: "dpb2"; + /// FEAT_DPB2 (aka dcpodp - data cache clean to point of deep persistence) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dotprod: "dotprod"; + /// FEAT_DotProd (Vector Dot-Product - ASIMDDP) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ecv: "ecv"; + /// FEAT_ECV (Enhanced Counter Virtualization) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] f32mm: "f32mm"; + /// FEAT_F32MM (single-precision matrix multiplication) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] f64mm: "f64mm"; + /// FEAT_F64MM (double-precision matrix multiplication) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] faminmax: "faminmax"; + /// FEAT_FAMINMAX (FAMIN and FAMAX SIMD/SVE/SME instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fcma: "fcma"; + /// FEAT_FCMA (float complex number operations) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fhm: "fhm"; + /// FEAT_FHM (fp16 multiplication instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] flagm: "flagm"; + /// FEAT_FLAGM (flag manipulation instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] flagm2: "flagm2"; + /// FEAT_FLAGM2 (flag manipulation instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp16: "fp16"; + /// FEAT_FP16 (Half-float support) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8: "fp8"; + /// FEAT_FP8 (F8CVT Instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8dot2: "fp8dot2"; + /// FEAT_FP8DOT2 (F8DP2 Instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8dot4: "fp8dot4"; + /// FEAT_FP8DOT4 (F8DP4 Instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8fma: "fp8fma"; + /// FEAT_FP8FMA (F8FMA Instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fpmr: "fpmr"; + without cfg check: true; + /// FEAT_FPMR (Special-purpose AArch64-FPMR register) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] frintts: "frintts"; + /// FEAT_FRINTTS (float to integer rounding instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] hbc: "hbc"; + /// FEAT_HBC (Hinted conditional branches) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] i8mm: "i8mm"; + /// FEAT_I8MM (integer matrix multiplication, plus ASIMD support) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] jsconv: "jsconv"; + /// FEAT_JSCVT (JavaScript float conversion instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] lse: "lse"; + /// FEAT_LSE (Large System Extension - atomics) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] lse128: "lse128"; + /// FEAT_LSE128 (128-bit atomics) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] lse2: "lse2"; + /// FEAT_LSE2 (unaligned and register-pair atomics) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] lut: "lut"; + /// FEAT_LUT (Lookup Table Instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] mops: "mops"; + /// FEAT_MOPS (Standardization of memory operations) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] mte: "mte"; + /// FEAT_MTE & FEAT_MTE2 (Memory Tagging Extension) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] paca: "paca"; + /// FEAT_PAuth (address authentication) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pacg: "pacg"; + /// FEAT_PAuth (generic authentication) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] pauth_lr: "pauth-lr"; + /// FEAT_PAuth_LR + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rand: "rand"; + /// FEAT_RNG (Random Number Generator) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rcpc: "rcpc"; + /// FEAT_LRCPC (Release consistent Processor consistent) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rcpc2: "rcpc2"; + /// FEAT_LRCPC2 (RCPC with immediate offsets) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] rcpc3: "rcpc3"; + /// FEAT_LRCPC3 (RCPC Instructions v3) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rdm: "rdm"; + /// FEAT_RDM (Rounding Doubling Multiply - ASIMDRDM) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sb: "sb"; + /// FEAT_SB (speculation barrier) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sha2: "sha2"; + /// FEAT_SHA1 & FEAT_SHA256 (SHA1 & SHA2-256 instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sha3: "sha3"; + /// FEAT_SHA512 & FEAT_SHA3 (SHA2-512 & SHA3 instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sm4: "sm4"; + /// FEAT_SM3 & FEAT_SM4 (SM3 & SM4 instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme: "sme"; + /// FEAT_SME (Scalable Matrix Extension) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme2: "sme2"; + /// FEAT_SME2 (SME Version 2) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme2p1: "sme2p1"; + /// FEAT_SME2p1 (SME Version 2.1) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_b16b16: "sme-b16b16"; + /// FEAT_SME_B16B16 + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f16f16: "sme-f16f16"; + /// FEAT_SME_F16F16 (Non-widening half-precision FP16 to FP16 arithmetic for SME2) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f64f64: "sme-f64f64"; + /// FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f8f16: "sme-f8f16"; + /// FEAT_SME_F8F16 + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f8f32: "sme-f8f32"; + /// FEAT_SME_F8F32 + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_fa64: "sme-fa64"; + /// FEAT_SME_FA64 (Full A64 instruction set support in Streaming SVE mode) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_i16i64: "sme-i16i64"; + /// FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_lutv2: "sme-lutv2"; + /// FEAT_SME_LUTv2 (LUTI4 Instruction) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] ssbs: "ssbs"; + /// FEAT_SSBS & FEAT_SSBS2 (speculative store bypass safe) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ssve_fp8dot2: "ssve-fp8dot2"; + /// FEAT_SSVE_FP8DOT2 + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ssve_fp8dot4: "ssve-fp8dot4"; + /// FEAT_SSVE_FP8DOT4 + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ssve_fp8fma: "ssve-fp8fma"; + /// FEAT_SSVE_FP8FMA + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve: "sve"; + /// FEAT_SVE (Scalable Vector Extension) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2: "sve2"; + /// FEAT_SVE2 (Scalable Vector Extension 2) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sve2p1: "sve2p1"; + /// FEAT_SVE2p1 (Scalable Vector Extension 2.1) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_aes: "sve2-aes"; + /// FEAT_SVE_AES & FEAT_SVE_PMULL128 (SVE2 AES crypto) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sve_b16b16: "sve-b16b16"; + /// FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_bitperm: "sve2-bitperm"; + /// FEAT_SVE_BitPerm (SVE2 bit permutation instructions) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_sha3: "sve2-sha3"; + /// FEAT_SVE_SHA3 (SVE2 SHA3 crypto) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_sm4: "sve2-sm4"; + /// FEAT_SVE_SM4 (SVE2 SM4 crypto) + @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] tme: "tme"; + /// FEAT_TME (Transactional Memory Extensions) + @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] wfxt: "wfxt"; + /// FEAT_WFxT (WFET and WFIT Instructions) +} diff --git a/library/std_detect/src/detect/arch/arm.rs b/library/std_detect/src/detect/arch/arm.rs new file mode 100644 index 00000000000..c3c8883ce31 --- /dev/null +++ b/library/std_detect/src/detect/arch/arm.rs @@ -0,0 +1,29 @@ +//! Run-time feature detection on ARM Aarch32. + +features! { + @TARGET: arm; + @CFG: target_arch = "arm"; + @MACRO_NAME: is_arm_feature_detected; + @MACRO_ATTRS: + /// Checks if `arm` feature is enabled. + #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] + @NO_RUNTIME_DETECTION: "v7"; + @NO_RUNTIME_DETECTION: "vfp2"; + @NO_RUNTIME_DETECTION: "vfp3"; + @NO_RUNTIME_DETECTION: "vfp4"; + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] neon: "neon"; + /// ARM Advanced SIMD (NEON) - Aarch32 + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] pmull: "pmull"; + without cfg check: true; + /// Polynomial Multiply + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] crc: "crc"; + /// CRC32 (Cyclic Redundancy Check) + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] aes: "aes"; + /// FEAT_AES (AES instructions) + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] sha2: "sha2"; + /// FEAT_SHA1 & FEAT_SHA256 (SHA1 & SHA2-256 instructions) + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] i8mm: "i8mm"; + /// FEAT_I8MM (integer matrix multiplication, plus ASIMD support) + @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] dotprod: "dotprod"; + /// FEAT_DotProd (Vector Dot-Product - ASIMDDP) +} diff --git a/library/std_detect/src/detect/arch/loongarch.rs b/library/std_detect/src/detect/arch/loongarch.rs new file mode 100644 index 00000000000..68fc600fa8e --- /dev/null +++ b/library/std_detect/src/detect/arch/loongarch.rs @@ -0,0 +1,51 @@ +//! Run-time feature detection on LoongArch. + +features! { + @TARGET: loongarch; + @CFG: any(target_arch = "loongarch32", target_arch = "loongarch64"); + @MACRO_NAME: is_loongarch_feature_detected; + @MACRO_ATTRS: + /// Checks if `loongarch` feature is enabled. + /// Supported arguments are: + /// + /// * `"f"` + /// * `"d"` + /// * `"frecipe"` + /// * `"div32"` + /// * `"lsx"` + /// * `"lasx"` + /// * `"lam-bh"` + /// * `"lamcas"` + /// * `"ld-seq-sa"` + /// * `"scq"` + /// * `"lbt"` + /// * `"lvz"` + /// * `"ual"` + #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] f: "f"; + /// F + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] d: "d"; + /// D + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] frecipe: "frecipe"; + /// Frecipe + @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] div32: "div32"; + /// Div32 + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lsx: "lsx"; + /// LSX + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lasx: "lasx"; + /// LASX + @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] lam_bh: "lam-bh"; + /// LAM-BH + @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] lamcas: "lamcas"; + /// LAM-CAS + @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] ld_seq_sa: "ld-seq-sa"; + /// LD-SEQ-SA + @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] scq: "scq"; + /// SCQ + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lbt: "lbt"; + /// LBT + @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lvz: "lvz"; + /// LVZ + @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] ual: "ual"; + /// UAL +} diff --git a/library/std_detect/src/detect/arch/mips.rs b/library/std_detect/src/detect/arch/mips.rs new file mode 100644 index 00000000000..e185fdfcaac --- /dev/null +++ b/library/std_detect/src/detect/arch/mips.rs @@ -0,0 +1,12 @@ +//! Run-time feature detection on MIPS. + +features! { + @TARGET: mips; + @CFG: target_arch = "mips"; + @MACRO_NAME: is_mips_feature_detected; + @MACRO_ATTRS: + /// Checks if `mips` feature is enabled. + #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] + @FEATURE: #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] msa: "msa"; + /// MIPS SIMD Architecture (MSA) +} diff --git a/library/std_detect/src/detect/arch/mips64.rs b/library/std_detect/src/detect/arch/mips64.rs new file mode 100644 index 00000000000..69fe4869d30 --- /dev/null +++ b/library/std_detect/src/detect/arch/mips64.rs @@ -0,0 +1,12 @@ +//! Run-time feature detection on MIPS64. + +features! { + @TARGET: mips64; + @CFG: target_arch = "mips64"; + @MACRO_NAME: is_mips64_feature_detected; + @MACRO_ATTRS: + /// Checks if `mips64` feature is enabled. + #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] + @FEATURE: #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] msa: "msa"; + /// MIPS SIMD Architecture (MSA) +} diff --git a/library/std_detect/src/detect/arch/mod.rs b/library/std_detect/src/detect/arch/mod.rs new file mode 100644 index 00000000000..b0be554ed89 --- /dev/null +++ b/library/std_detect/src/detect/arch/mod.rs @@ -0,0 +1,75 @@ +#![allow(dead_code)] + +use cfg_if::cfg_if; + +// Export the macros for all supported architectures. +#[macro_use] +mod x86; +#[macro_use] +mod arm; +#[macro_use] +mod aarch64; +#[macro_use] +mod riscv; +#[macro_use] +mod powerpc; +#[macro_use] +mod powerpc64; +#[macro_use] +mod mips; +#[macro_use] +mod mips64; +#[macro_use] +mod loongarch; +#[macro_use] +mod s390x; + +cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + #[stable(feature = "simd_x86", since = "1.27.0")] + pub use x86::*; + } else if #[cfg(target_arch = "arm")] { + #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] + pub use arm::*; + } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { + #[stable(feature = "simd_aarch64", since = "1.60.0")] + pub use aarch64::*; + } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { + #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] + pub use riscv::*; + } else if #[cfg(target_arch = "powerpc")] { + #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] + pub use powerpc::*; + } else if #[cfg(target_arch = "powerpc64")] { + #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] + pub use powerpc64::*; + } else if #[cfg(target_arch = "mips")] { + #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] + pub use mips::*; + } else if #[cfg(target_arch = "mips64")] { + #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] + pub use mips64::*; + } else if #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] { + #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] + pub use loongarch::*; + } else if #[cfg(target_arch = "s390x")] { + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + pub use s390x::*; + } else { + // Unimplemented architecture: + #[doc(hidden)] + pub(crate) enum Feature { + Null + } + #[doc(hidden)] + #[unstable(feature = "stdarch_internal", issue = "none")] + pub mod __is_feature_detected {} + + impl Feature { + #[doc(hidden)] + pub(crate) fn from_str(_s: &str) -> Result { Err(()) } + #[doc(hidden)] + pub(crate) fn to_str(self) -> &'static str { "" } + } + } +} diff --git a/library/std_detect/src/detect/arch/powerpc.rs b/library/std_detect/src/detect/arch/powerpc.rs new file mode 100644 index 00000000000..c390993a48a --- /dev/null +++ b/library/std_detect/src/detect/arch/powerpc.rs @@ -0,0 +1,30 @@ +//! Run-time feature detection on PowerPC. + +features! { + @TARGET: powerpc; + @CFG: target_arch = "powerpc"; + @MACRO_NAME: is_powerpc_feature_detected; + @MACRO_ATTRS: + /// Checks if `powerpc` feature is enabled. + #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] altivec: "altivec"; + /// Altivec + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] vsx: "vsx"; + /// VSX + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8: "power8"; + without cfg check: true; + /// Power8 + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_altivec: "power8-altivec"; + /// Power8 altivec + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_vector: "power8-vector"; + /// Power8 vector + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_crypto: "power8-crypto"; + /// Power8 crypto + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9: "power9"; + without cfg check: true; + /// Power9 + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_altivec: "power9-altivec"; + /// Power9 altivec + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_vector: "power9-vector"; + /// Power9 vector +} diff --git a/library/std_detect/src/detect/arch/powerpc64.rs b/library/std_detect/src/detect/arch/powerpc64.rs new file mode 100644 index 00000000000..cf05baa6f79 --- /dev/null +++ b/library/std_detect/src/detect/arch/powerpc64.rs @@ -0,0 +1,30 @@ +//! Run-time feature detection on PowerPC64. + +features! { + @TARGET: powerpc64; + @CFG: target_arch = "powerpc64"; + @MACRO_NAME: is_powerpc64_feature_detected; + @MACRO_ATTRS: + /// Checks if `powerpc` feature is enabled. + #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] altivec: "altivec"; + /// Altivec + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] vsx: "vsx"; + /// VSX + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8: "power8"; + without cfg check: true; + /// Power8 + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_altivec: "power8-altivec"; + /// Power8 altivec + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_vector: "power8-vector"; + /// Power8 vector + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_crypto: "power8-crypto"; + /// Power8 crypto + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9: "power9"; + without cfg check: true; + /// Power9 + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_altivec: "power9-altivec"; + /// Power9 altivec + @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_vector: "power9-vector"; + /// Power9 vector +} diff --git a/library/std_detect/src/detect/arch/riscv.rs b/library/std_detect/src/detect/arch/riscv.rs new file mode 100644 index 00000000000..b86190d7bbf --- /dev/null +++ b/library/std_detect/src/detect/arch/riscv.rs @@ -0,0 +1,344 @@ +//! Run-time feature detection on RISC-V. + +features! { + @TARGET: riscv; + @CFG: any(target_arch = "riscv32", target_arch = "riscv64"); + @MACRO_NAME: is_riscv_feature_detected; + @MACRO_ATTRS: + /// A macro to test at *runtime* whether instruction sets are available on + /// RISC-V platforms. + /// + /// RISC-V standard defined the base sets and the extension sets. + /// The base sets are RV32I, RV64I, RV32E or RV128I. Any RISC-V platform + /// must support one base set and/or multiple extension sets. + /// + /// Any RISC-V standard instruction sets can be in state of either ratified, + /// frozen or draft. The version and status of current standard instruction + /// sets can be checked out from preface section of the [ISA manual]. + /// + /// Platform may define and support their own custom instruction sets with + /// ISA prefix X. These sets are highly platform specific and should be + /// detected with their own platform support crates. + /// + /// [ISA manual]: https://riscv.org/specifications/ratified/ + /// + /// # Platform-specific/agnostic Behavior and Availability + /// + /// Runtime detection depends on the platform-specific feature detection + /// facility and its availability per feature is + /// highly platform/version-specific. + /// + /// Still, a best-effort attempt is performed to enable subset/dependent + /// features if a superset feature is enabled regardless of the platform. + /// For instance, if the A extension (`"a"`) is enabled, its subsets (the + /// Zalrsc and Zaamo extensions; `"zalrsc"` and `"zaamo"`) are also enabled. + /// Likewise, if the F extension (`"f"`) is enabled, one of its dependencies + /// (the Zicsr extension `"zicsr"`) is also enabled. + /// + /// # Unprivileged Specification + /// + /// The supported ratified RISC-V instruction sets are as follows: + /// + /// * RV32E: `"rv32e"` + /// * RV32I: `"rv32i"` + /// * RV64I: `"rv64i"` + /// * A: `"a"` + /// * Zaamo: `"zaamo"` + /// * Zalrsc: `"zalrsc"` + /// * B: `"b"` + /// * Zba: `"zba"` + /// * Zbb: `"zbb"` + /// * Zbs: `"zbs"` + /// * C: `"c"` + /// * Zca: `"zca"` + /// * Zcd: `"zcd"` (if D is enabled) + /// * Zcf: `"zcf"` (if F is enabled on RV32) + /// * D: `"d"` + /// * F: `"f"` + /// * M: `"m"` + /// * Q: `"q"` + /// * V: `"v"` + /// * Zve32x: `"zve32x"` + /// * Zve32f: `"zve32f"` + /// * Zve64x: `"zve64x"` + /// * Zve64f: `"zve64f"` + /// * Zve64d: `"zve64d"` + /// * Zicbom: `"zicbom"` + /// * Zicboz: `"zicboz"` + /// * Zicntr: `"zicntr"` + /// * Zicond: `"zicond"` + /// * Zicsr: `"zicsr"` + /// * Zifencei: `"zifencei"` + /// * Zihintntl: `"zihintntl"` + /// * Zihintpause: `"zihintpause"` + /// * Zihpm: `"zihpm"` + /// * Zimop: `"zimop"` + /// * Zacas: `"zacas"` + /// * Zawrs: `"zawrs"` + /// * Zfa: `"zfa"` + /// * Zfbfmin: `"zfbfmin"` + /// * Zfh: `"zfh"` + /// * Zfhmin: `"zfhmin"` + /// * Zfinx: `"zfinx"` + /// * Zdinx: `"zdinx"` + /// * Zhinx: `"zhinx"` + /// * Zhinxmin: `"zhinxmin"` + /// * Zcb: `"zcb"` + /// * Zcmop: `"zcmop"` + /// * Zbc: `"zbc"` + /// * Zbkb: `"zbkb"` + /// * Zbkc: `"zbkc"` + /// * Zbkx: `"zbkx"` + /// * Zk: `"zk"` + /// * Zkn: `"zkn"` + /// * Zknd: `"zknd"` + /// * Zkne: `"zkne"` + /// * Zknh: `"zknh"` + /// * Zkr: `"zkr"` + /// * Zks: `"zks"` + /// * Zksed: `"zksed"` + /// * Zksh: `"zksh"` + /// * Zkt: `"zkt"` + /// * Zvbb: `"zvbb"` + /// * Zvbc: `"zvbc"` + /// * Zvfbfmin: `"zvfbfmin"` + /// * Zvfbfwma: `"zvfbfwma"` + /// * Zvfh: `"zvfh"` + /// * Zvfhmin: `"zvfhmin"` + /// * Zvkb: `"zvkb"` + /// * Zvkg: `"zvkg"` + /// * Zvkn: `"zvkn"` + /// * Zvkned: `"zvkned"` + /// * Zvknha: `"zvknha"` + /// * Zvknhb: `"zvknhb"` + /// * Zvknc: `"zvknc"` + /// * Zvkng: `"zvkng"` + /// * Zvks: `"zvks"` + /// * Zvksed: `"zvksed"` + /// * Zvksh: `"zvksh"` + /// * Zvksc: `"zvksc"` + /// * Zvksg: `"zvksg"` + /// * Zvkt: `"zvkt"` + /// * Ztso: `"ztso"` + /// + /// There's also bases and extensions marked as standard instruction set, + /// but they are in frozen or draft state. These instruction sets are also + /// reserved by this macro and can be detected in the future platforms. + /// + /// Draft RISC-V instruction sets: + /// + /// * RV128I: `"rv128i"` + /// * J: `"j"` + /// * P: `"p"` + /// * Zam: `"zam"` + /// + /// # Performance Hints + /// + /// The two features below define performance hints for unaligned + /// scalar/vector memory accesses, respectively. If enabled, it denotes that + /// corresponding unaligned memory access is reasonably fast. + /// + /// * `"unaligned-scalar-mem"` + /// * Runtime detection requires Linux kernel version 6.4 or later. + /// * `"unaligned-vector-mem"` + /// * Runtime detection requires Linux kernel version 6.13 or later. + #[stable(feature = "riscv_ratified", since = "1.78.0")] + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv32i: "rv32i"; + without cfg check: true; + /// RV32I Base Integer Instruction Set + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv32e: "rv32e"; + without cfg check: true; + /// RV32E Base Integer Instruction Set + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv64i: "rv64i"; + without cfg check: true; + /// RV64I Base Integer Instruction Set + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv128i: "rv128i"; + without cfg check: true; + /// RV128I Base Integer Instruction Set + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_scalar_mem: "unaligned-scalar-mem"; + /// Has reasonably performant unaligned scalar + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_vector_mem: "unaligned-vector-mem"; + /// Has reasonably performant unaligned vector + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicsr: "zicsr"; + /// "Zicsr" Extension for Control and Status Register (CSR) Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicntr: "zicntr"; + /// "Zicntr" Extension for Base Counters and Timers + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihpm: "zihpm"; + /// "Zihpm" Extension for Hardware Performance Counters + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zifencei: "zifencei"; + /// "Zifencei" Extension for Instruction-Fetch Fence + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihintntl: "zihintntl"; + /// "Zihintntl" Extension for Non-Temporal Locality Hints + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihintpause: "zihintpause"; + /// "Zihintpause" Extension for Pause Hint + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zimop: "zimop"; + /// "Zimop" Extension for May-Be-Operations + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicbom: "zicbom"; + /// "Zicbom" Extension for Cache-Block Management Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicboz: "zicboz"; + /// "Zicboz" Extension for Cache-Block Zero Instruction + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicond: "zicond"; + /// "Zicond" Extension for Integer Conditional Operations + + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] m: "m"; + /// "M" Extension for Integer Multiplication and Division + + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] a: "a"; + /// "A" Extension for Atomic Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zalrsc: "zalrsc"; + /// "Zalrsc" Extension for Load-Reserved/Store-Conditional Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zaamo: "zaamo"; + /// "Zaamo" Extension for Atomic Memory Operations + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zawrs: "zawrs"; + /// "Zawrs" Extension for Wait-on-Reservation-Set Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zacas: "zacas"; + /// "Zacas" Extension for Atomic Compare-and-Swap (CAS) Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zam: "zam"; + without cfg check: true; + /// "Zam" Extension for Misaligned Atomics + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] ztso: "ztso"; + /// "Ztso" Extension for Total Store Ordering + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] f: "f"; + /// "F" Extension for Single-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] d: "d"; + /// "D" Extension for Double-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] q: "q"; + without cfg check: true; + /// "Q" Extension for Quad-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfh: "zfh"; + /// "Zfh" Extension for Half-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfhmin: "zfhmin"; + /// "Zfhmin" Extension for Minimal Half-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfa: "zfa"; + /// "Zfa" Extension for Additional Floating-Point Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfbfmin: "zfbfmin"; + /// "Zfbfmin" Extension for Scalar BF16 Converts + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfinx: "zfinx"; + /// "Zfinx" Extension for Single-Precision Floating-Point in Integer Registers + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zdinx: "zdinx"; + /// "Zdinx" Extension for Double-Precision Floating-Point in Integer Registers + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zhinx: "zhinx"; + /// "Zhinx" Extension for Half-Precision Floating-Point in Integer Registers + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zhinxmin: "zhinxmin"; + /// "Zhinxmin" Extension for Minimal Half-Precision Floating-Point in Integer Registers + + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] c: "c"; + /// "C" Extension for Compressed Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zca: "zca"; + /// "Zca" Compressed Instructions excluding Floating-Point Loads/Stores + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcf: "zcf"; + without cfg check: true; + /// "Zcf" Compressed Instructions for Single-Precision Floating-Point Loads/Stores on RV32 + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcd: "zcd"; + without cfg check: true; + /// "Zcd" Compressed Instructions for Double-Precision Floating-Point Loads/Stores + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcb: "zcb"; + /// "Zcb" Simple Code-size Saving Compressed Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcmop: "zcmop"; + /// "Zcmop" Extension for Compressed May-Be-Operations + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] b: "b"; + /// "B" Extension for Bit Manipulation + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zba: "zba"; + /// "Zba" Extension for Address Generation + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbb: "zbb"; + /// "Zbb" Extension for Basic Bit-Manipulation + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbc: "zbc"; + /// "Zbc" Extension for Carry-less Multiplication + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbs: "zbs"; + /// "Zbs" Extension for Single-Bit Instructions + + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbkb: "zbkb"; + /// "Zbkb" Extension for Bit-Manipulation for Cryptography + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbkc: "zbkc"; + /// "Zbkc" Extension for Carry-less Multiplication for Cryptography + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbkx: "zbkx"; + /// "Zbkx" Extension for Crossbar Permutations + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zknd: "zknd"; + /// "Zknd" Cryptography Extension for NIST Suite: AES Decryption + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkne: "zkne"; + /// "Zkne" Cryptography Extension for NIST Suite: AES Encryption + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zknh: "zknh"; + /// "Zknh" Cryptography Extension for NIST Suite: Hash Function Instructions + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zksed: "zksed"; + /// "Zksed" Cryptography Extension for ShangMi Suite: SM4 Block Cipher Instructions + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zksh: "zksh"; + /// "Zksh" Cryptography Extension for ShangMi Suite: SM3 Hash Function Instructions + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkr: "zkr"; + /// "Zkr" Entropy Source Extension + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkn: "zkn"; + /// "Zkn" Cryptography Extension for NIST Algorithm Suite + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zks: "zks"; + /// "Zks" Cryptography Extension for ShangMi Algorithm Suite + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zk: "zk"; + /// "Zk" Cryptography Extension for Standard Scalar Cryptography + @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkt: "zkt"; + /// "Zkt" Cryptography Extension for Data Independent Execution Latency + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] v: "v"; + /// "V" Extension for Vector Operations + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32x: "zve32x"; + /// "Zve32x" Vector Extension for Embedded Processors (32-bit+; Integer) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32f: "zve32f"; + /// "Zve32f" Vector Extension for Embedded Processors (32-bit+; with Single-Precision Floating-Point) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64x: "zve64x"; + /// "Zve64x" Vector Extension for Embedded Processors (64-bit+; Integer) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64f: "zve64f"; + /// "Zve64f" Vector Extension for Embedded Processors (64-bit+; with Single-Precision Floating-Point) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64d: "zve64d"; + /// "Zve64d" Vector Extension for Embedded Processors (64-bit+; with Double-Precision Floating-Point) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfh: "zvfh"; + /// "Zvfh" Vector Extension for Half-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfhmin: "zvfhmin"; + /// "Zvfhmin" Vector Extension for Minimal Half-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfbfmin: "zvfbfmin"; + /// "Zvfbfmin" Vector Extension for BF16 Converts + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfbfwma: "zvfbfwma"; + /// "Zvfbfwma" Vector Extension for BF16 Widening Multiply-Add + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbb: "zvbb"; + /// "Zvbb" Extension for Vector Basic Bit-Manipulation + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbc: "zvbc"; + /// "Zvbc" Extension for Vector Carryless Multiplication + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkb: "zvkb"; + /// "Zvkb" Extension for Vector Cryptography Bit-Manipulation + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkg: "zvkg"; + /// "Zvkg" Cryptography Extension for Vector GCM/GMAC + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkned: "zvkned"; + /// "Zvkned" Cryptography Extension for NIST Suite: Vector AES Block Cipher + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknha: "zvknha"; + /// "Zvknha" Cryptography Extension for Vector SHA-2 Secure Hash (SHA-256) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknhb: "zvknhb"; + /// "Zvknhb" Cryptography Extension for Vector SHA-2 Secure Hash (SHA-256/512) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksed: "zvksed"; + /// "Zvksed" Cryptography Extension for ShangMi Suite: Vector SM4 Block Cipher + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksh: "zvksh"; + /// "Zvksh" Cryptography Extension for ShangMi Suite: Vector SM3 Secure Hash + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkn: "zvkn"; + /// "Zvkn" Cryptography Extension for NIST Algorithm Suite + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknc: "zvknc"; + /// "Zvknc" Cryptography Extension for NIST Algorithm Suite with Carryless Multiply + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkng: "zvkng"; + /// "Zvkng" Cryptography Extension for NIST Algorithm Suite with GCM + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvks: "zvks"; + /// "Zvks" Cryptography Extension for ShangMi Algorithm Suite + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksc: "zvksc"; + /// "Zvksc" Cryptography Extension for ShangMi Algorithm Suite with Carryless Multiply + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksg: "zvksg"; + /// "Zvksg" Cryptography Extension for ShangMi Algorithm Suite with GCM + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkt: "zvkt"; + /// "Zvkt" Extension for Vector Data-Independent Execution Latency + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] j: "j"; + without cfg check: true; + /// "J" Extension for Dynamically Translated Languages + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] p: "p"; + without cfg check: true; + /// "P" Extension for Packed-SIMD Instructions +} diff --git a/library/std_detect/src/detect/arch/s390x.rs b/library/std_detect/src/detect/arch/s390x.rs new file mode 100644 index 00000000000..4c20d011680 --- /dev/null +++ b/library/std_detect/src/detect/arch/s390x.rs @@ -0,0 +1,81 @@ +//! Run-time feature detection on s390x. + +features! { + @TARGET: s390x; + @CFG: target_arch = "s390x"; + @MACRO_NAME: is_s390x_feature_detected; + @MACRO_ATTRS: + /// Checks if `s390x` feature is enabled. + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] concurrent_functions: "concurrent-functions"; + /// s390x concurrent-functions facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] deflate_conversion: "deflate-conversion"; + /// s390x deflate-conversion facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] enhanced_sort: "enhanced-sort"; + /// s390x enhanced-sort facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] guarded_storage: "guarded-storage"; + /// s390x guarded-storage facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] high_word: "high-word"; + /// s390x high-word facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension3: "message-security-assist-extension3"; + /// s390x message-security-assist-extension3 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension4: "message-security-assist-extension4"; + /// s390x message-security-assist-extension4 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension5: "message-security-assist-extension5"; + /// s390x message-security-assist-extension5 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension8: "message-security-assist-extension8"; + /// s390x message-security-assist-extension8 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension9: "message-security-assist-extension9"; + /// s390x message-security-assist-extension9 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension12: "message-security-assist-extension12"; + /// s390x message-security-assist-extension12 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] miscellaneous_extensions_2: "miscellaneous-extensions-2"; + /// s390x miscellaneous-extensions-2 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] miscellaneous_extensions_3: "miscellaneous-extensions-3"; + /// s390x miscellaneous-extensions-3 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] miscellaneous_extensions_4: "miscellaneous-extensions-4"; + /// s390x miscellaneous-extensions-4 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] nnp_assist: "nnp-assist"; + /// s390x nnp-assist facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] transactional_execution: "transactional-execution"; + /// s390x transactional-execution facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector: "vector"; + /// s390x vector facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_enhancements_1: "vector-enhancements-1"; + /// s390x vector-enhancements-1 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_enhancements_2: "vector-enhancements-2"; + /// s390x vector-enhancements-2 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_enhancements_3: "vector-enhancements-3"; + /// s390x vector-enhancements-3 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal: "vector-packed-decimal"; + /// s390x vector-packed-decimal facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal_enhancement: "vector-packed-decimal-enhancement"; + /// s390x vector-packed-decimal-enhancement facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal_enhancement_2: "vector-packed-decimal-enhancement-2"; + /// s390x vector-packed-decimal-enhancement-2 facility + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal_enhancement_3: "vector-packed-decimal-enhancement-3"; + /// s390x vector-packed-decimal-enhancement-3 facility +} diff --git a/library/std_detect/src/detect/arch/x86.rs b/library/std_detect/src/detect/arch/x86.rs new file mode 100644 index 00000000000..28b3e3cfb35 --- /dev/null +++ b/library/std_detect/src/detect/arch/x86.rs @@ -0,0 +1,278 @@ +//! This module implements minimal run-time feature detection for x86. +//! +//! The features are detected using the `detect_features` function below. +//! This function uses the CPUID instruction to read the feature flags from the +//! CPU and encodes them in a `usize` where each bit position represents +//! whether a feature is available (bit is set) or unavailable (bit is cleared). +//! +//! The enum `Feature` is used to map bit positions to feature names, and the +//! the `__crate::detect::check_for!` macro is used to map string literals (e.g., +//! "avx") to these bit positions (e.g., `Feature::avx`). +//! +//! The run-time feature detection is performed by the +//! `__crate::detect::check_for(Feature) -> bool` function. On its first call, +//! this functions queries the CPU for the available features and stores them +//! in a global `AtomicUsize` variable. The query is performed by just checking +//! whether the feature bit in this global variable is set or cleared. + +features! { + @TARGET: x86; + @CFG: any(target_arch = "x86", target_arch = "x86_64"); + @MACRO_NAME: is_x86_feature_detected; + @MACRO_ATTRS: + /// A macro to test at *runtime* whether a CPU feature is available on + /// x86/x86-64 platforms. + /// + /// This macro is provided in the standard library and will detect at runtime + /// whether the specified CPU feature is detected. This does **not** resolve at + /// compile time unless the specified feature is already enabled for the entire + /// crate. Runtime detection currently relies mostly on the `cpuid` instruction. + /// + /// This macro only takes one argument which is a string literal of the feature + /// being tested for. The feature names supported are the lowercase versions of + /// the ones defined by Intel in [their documentation][docs]. + /// + /// ## Supported arguments + /// + /// This macro supports the same names that `#[target_feature]` supports. Unlike + /// `#[target_feature]`, however, this macro does not support names separated + /// with a comma. Instead testing for multiple features must be done through + /// separate macro invocations for now. + /// + /// Supported arguments are: + /// + /// * `"aes"` + /// * `"pclmulqdq"` + /// * `"rdrand"` + /// * `"rdseed"` + /// * `"tsc"` + /// * `"mmx"` + /// * `"sse"` + /// * `"sse2"` + /// * `"sse3"` + /// * `"ssse3"` + /// * `"sse4.1"` + /// * `"sse4.2"` + /// * `"sse4a"` + /// * `"sha"` + /// * `"avx"` + /// * `"avx2"` + /// * `"sha512"` + /// * `"sm3"` + /// * `"sm4"` + /// * `"avx512f"` + /// * `"avx512cd"` + /// * `"avx512er"` + /// * `"avx512pf"` + /// * `"avx512bw"` + /// * `"avx512dq"` + /// * `"avx512vl"` + /// * `"avx512ifma"` + /// * `"avx512vbmi"` + /// * `"avx512vpopcntdq"` + /// * `"avx512vbmi2"` + /// * `"gfni"` + /// * `"vaes"` + /// * `"vpclmulqdq"` + /// * `"avx512vnni"` + /// * `"avx512bitalg"` + /// * `"avx512bf16"` + /// * `"avx512vp2intersect"` + /// * `"avx512fp16"` + /// * `"avxvnni"` + /// * `"avxifma"` + /// * `"avxneconvert"` + /// * `"avxvnniint8"` + /// * `"avxvnniint16"` + /// * `"amx-tile"` + /// * `"amx-int8"` + /// * `"amx-bf16"` + /// * `"amx-fp16"` + /// * `"amx-complex"` + /// * `"amx-avx512"` + /// * `"amx-fp8"` + /// * `"amx-movrs"` + /// * `"amx-tf32"` + /// * `"amx-transpose"` + /// * `"f16c"` + /// * `"fma"` + /// * `"bmi1"` + /// * `"bmi2"` + /// * `"abm"` + /// * `"lzcnt"` + /// * `"tbm"` + /// * `"popcnt"` + /// * `"fxsr"` + /// * `"xsave"` + /// * `"xsaveopt"` + /// * `"xsaves"` + /// * `"xsavec"` + /// * `"cmpxchg16b"` + /// * `"kl"` + /// * `"widekl"` + /// * `"adx"` + /// * `"rtm"` + /// * `"movbe"` + /// * `"ermsb"` + /// * `"movrs"` + /// * `"xop"` + /// + /// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide + #[stable(feature = "simd_x86", since = "1.27.0")] + @BIND_FEATURE_NAME: "abm"; "lzcnt"; // abm is a synonym for lzcnt + @BIND_FEATURE_NAME: "avx512gfni"; "gfni"; #[deprecated(since = "1.67.0", note = "the `avx512gfni` feature has been renamed to `gfni`")]; + @BIND_FEATURE_NAME: "avx512vaes"; "vaes"; #[deprecated(since = "1.67.0", note = "the `avx512vaes` feature has been renamed to `vaes`")]; + @BIND_FEATURE_NAME: "avx512vpclmulqdq"; "vpclmulqdq"; #[deprecated(since = "1.67.0", note = "the `avx512vpclmulqdq` feature has been renamed to `vpclmulqdq`")]; + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] aes: "aes"; + /// AES (Advanced Encryption Standard New Instructions AES-NI) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] pclmulqdq: "pclmulqdq"; + /// CLMUL (Carry-less Multiplication) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rdrand: "rdrand"; + /// RDRAND + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rdseed: "rdseed"; + /// RDSEED + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] tsc: "tsc"; + without cfg check: true; + /// TSC (Time Stamp Counter) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] mmx: "mmx"; + without cfg check: true; + /// MMX (MultiMedia eXtensions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse: "sse"; + /// SSE (Streaming SIMD Extensions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse2: "sse2"; + /// SSE2 (Streaming SIMD Extensions 2) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse3: "sse3"; + /// SSE3 (Streaming SIMD Extensions 3) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] ssse3: "ssse3"; + /// SSSE3 (Supplemental Streaming SIMD Extensions 3) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4_1: "sse4.1"; + /// SSE4.1 (Streaming SIMD Extensions 4.1) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4_2: "sse4.2"; + /// SSE4.2 (Streaming SIMD Extensions 4.2) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4a: "sse4a"; + /// SSE4a (Streaming SIMD Extensions 4a) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sha: "sha"; + /// SHA + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx: "avx"; + /// AVX (Advanced Vector Extensions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx2: "avx2"; + /// AVX2 (Advanced Vector Extensions 2) + @FEATURE: #[stable(feature = "sha512_sm_x86", since = "1.89.0")] sha512: "sha512"; + /// SHA512 + @FEATURE: #[stable(feature = "sha512_sm_x86", since = "1.89.0")] sm3: "sm3"; + /// SM3 + @FEATURE: #[stable(feature = "sha512_sm_x86", since = "1.89.0")] sm4: "sm4"; + /// SM4 + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512f: "avx512f" ; + /// AVX-512 F (Foundation) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512cd: "avx512cd" ; + /// AVX-512 CD (Conflict Detection Instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512er: "avx512er"; + without cfg check: true; + /// AVX-512 ER (Expo nential and Reciprocal Instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512pf: "avx512pf"; + without cfg check: true; + /// AVX-512 PF (Prefetch Instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512bw: "avx512bw"; + /// AVX-512 BW (Byte and Word Instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512dq: "avx512dq"; + /// AVX-512 DQ (Doubleword and Quadword) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vl: "avx512vl"; + /// AVX-512 VL (Vector Length Extensions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512ifma: "avx512ifma"; + /// AVX-512 IFMA (Integer Fused Multiply Add) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vbmi: "avx512vbmi"; + /// AVX-512 VBMI (Vector Byte Manipulation Instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vpopcntdq: "avx512vpopcntdq"; + /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and Quadword) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vbmi2: "avx512vbmi2"; + /// AVX-512 VBMI2 (Additional byte, word, dword and qword capabilities) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] gfni: "gfni"; + /// AVX-512 GFNI (Galois Field New Instruction) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] vaes: "vaes"; + /// AVX-512 VAES (Vector AES instruction) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] vpclmulqdq: "vpclmulqdq"; + /// AVX-512 VPCLMULQDQ (Vector PCLMULQDQ instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vnni: "avx512vnni"; + /// AVX-512 VNNI (Vector Neural Network Instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512bitalg: "avx512bitalg"; + /// AVX-512 BITALG (Support for VPOPCNT\[B,W\] and VPSHUFBITQMB) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512bf16: "avx512bf16"; + /// AVX-512 BF16 (BFLOAT16 instructions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vp2intersect: "avx512vp2intersect"; + /// AVX-512 P2INTERSECT + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512fp16: "avx512fp16"; + /// AVX-512 FP16 (FLOAT16 instructions) + @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxifma: "avxifma"; + /// AVX-IFMA (Integer Fused Multiply Add) + @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxneconvert: "avxneconvert"; + /// AVX-NE-CONVERT (Exceptionless Convert) + @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxvnni: "avxvnni"; + /// AVX-VNNI (Vector Neural Network Instructions) + @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxvnniint16: "avxvnniint16"; + /// AVX-VNNI_INT8 (VNNI with 16-bit Integers) + @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxvnniint8: "avxvnniint8"; + /// AVX-VNNI_INT16 (VNNI with 8-bit integers) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_tile: "amx-tile"; + /// AMX (Advanced Matrix Extensions) - Tile load/store + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_int8: "amx-int8"; + /// AMX-INT8 (Operations on 8-bit integers) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_bf16: "amx-bf16"; + /// AMX-BF16 (BFloat16 Operations) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_fp16: "amx-fp16"; + /// AMX-FP16 (Float16 Operations) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_complex: "amx-complex"; + /// AMX-COMPLEX (Complex number Operations) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_avx512: "amx-avx512"; + /// AMX-AVX512 (AVX512 operations extended to matrices) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_fp8: "amx-fp8"; + /// AMX-FP8 (Float8 Operations) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_movrs: "amx-movrs"; + /// AMX-MOVRS (Matrix MOVERS operations) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_tf32: "amx-tf32"; + /// AMX-TF32 (TensorFloat32 Operations) + @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_transpose: "amx-transpose"; + /// AMX-TRANSPOSE (Matrix Transpose Operations) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] f16c: "f16c"; + /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fma: "fma"; + /// FMA (Fused Multiply Add) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] bmi1: "bmi1" ; + /// BMI1 (Bit Manipulation Instructions 1) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] bmi2: "bmi2" ; + /// BMI2 (Bit Manipulation Instructions 2) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] lzcnt: "lzcnt"; + /// ABM (Advanced Bit Manipulation) / LZCNT (Leading Zero Count) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] tbm: "tbm"; + /// TBM (Trailing Bit Manipulation) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] popcnt: "popcnt"; + /// POPCNT (Population Count) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fxsr: "fxsr"; + /// FXSR (Floating-point context fast save and restore) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsave: "xsave"; + /// XSAVE (Save Processor Extended States) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsaveopt: "xsaveopt"; + /// XSAVEOPT (Save Processor Extended States Optimized) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsaves: "xsaves"; + /// XSAVES (Save Processor Extended States Supervisor) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsavec: "xsavec"; + /// XSAVEC (Save Processor Extended States Compacted) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] cmpxchg16b: "cmpxchg16b"; + /// CMPXCH16B (16-byte compare-and-swap instruction) + @FEATURE: #[stable(feature = "keylocker_x86", since = "1.89.0")] kl: "kl"; + /// Intel Key Locker + @FEATURE: #[stable(feature = "keylocker_x86", since = "1.89.0")] widekl: "widekl"; + /// Intel Key Locker Wide + @FEATURE: #[stable(feature = "simd_x86_adx", since = "1.33.0")] adx: "adx"; + /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rtm: "rtm"; + /// RTM, Intel (Restricted Transactional Memory) + @FEATURE: #[stable(feature = "movbe_target_feature", since = "1.67.0")] movbe: "movbe"; + /// MOVBE (Move Data After Swapping Bytes) + @FEATURE: #[unstable(feature = "movrs_target_feature", issue = "137976")] movrs: "movrs"; + /// MOVRS (Move data with the read-shared hint) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] ermsb: "ermsb"; + /// ERMSB, Enhanced REP MOVSB and STOSB + @FEATURE: #[unstable(feature = "xop_target_feature", issue = "127208")] xop: "xop"; + /// XOP: eXtended Operations (AMD) +} diff --git a/library/std_detect/src/detect/bit.rs b/library/std_detect/src/detect/bit.rs new file mode 100644 index 00000000000..6f06c5523e4 --- /dev/null +++ b/library/std_detect/src/detect/bit.rs @@ -0,0 +1,9 @@ +//! Bit manipulation utilities. + +/// Tests the `bit` of `x`. +#[allow(dead_code)] +#[inline] +pub(crate) fn test(x: usize, bit: u32) -> bool { + debug_assert!(bit < usize::BITS, "bit index out-of-bounds"); + x & (1 << bit) != 0 +} diff --git a/library/std_detect/src/detect/cache.rs b/library/std_detect/src/detect/cache.rs new file mode 100644 index 00000000000..83bcedea612 --- /dev/null +++ b/library/std_detect/src/detect/cache.rs @@ -0,0 +1,223 @@ +//! Caches run-time feature detection so that it only needs to be computed +//! once. + +#![allow(dead_code)] // not used on all platforms + +use core::sync::atomic::Ordering; + +use core::sync::atomic::AtomicUsize; + +/// Sets the `bit` of `x`. +#[inline] +const fn set_bit(x: u128, bit: u32) -> u128 { + x | 1 << bit +} + +/// Tests the `bit` of `x`. +#[inline] +const fn test_bit(x: u128, bit: u32) -> bool { + x & (1 << bit) != 0 +} + +/// Unset the `bit of `x`. +#[inline] +const fn unset_bit(x: u128, bit: u32) -> u128 { + x & !(1 << bit) +} + +/// Maximum number of features that can be cached. +const CACHE_CAPACITY: u32 = 93; + +/// This type is used to initialize the cache +// The derived `Default` implementation will initialize the field to zero, +// which is what we want. +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub(crate) struct Initializer(u128); + +// NOTE: the `debug_assert!` would catch that we do not add more Features than +// the one fitting our cache. +impl Initializer { + /// Tests the `bit` of the cache. + #[inline] + pub(crate) fn test(self, bit: u32) -> bool { + debug_assert!( + bit < CACHE_CAPACITY, + "too many features, time to increase the cache size!" + ); + test_bit(self.0, bit) + } + + /// Sets the `bit` of the cache. + #[inline] + pub(crate) fn set(&mut self, bit: u32) { + debug_assert!( + bit < CACHE_CAPACITY, + "too many features, time to increase the cache size!" + ); + let v = self.0; + self.0 = set_bit(v, bit); + } + + /// Unsets the `bit` of the cache. + #[inline] + pub(crate) fn unset(&mut self, bit: u32) { + debug_assert!( + bit < CACHE_CAPACITY, + "too many features, time to increase the cache size!" + ); + let v = self.0; + self.0 = unset_bit(v, bit); + } +} + +/// This global variable is a cache of the features supported by the CPU. +// Note: the third slot is only used in x86 +// Another Slot can be added if needed without any change to `Initializer` +static CACHE: [Cache; 3] = [ + Cache::uninitialized(), + Cache::uninitialized(), + Cache::uninitialized(), +]; + +/// Feature cache with capacity for `size_of::() * 8 - 1` features. +/// +/// Note: 0 is used to represent an uninitialized cache, and (at least) the most +/// significant bit is set on any cache which has been initialized. +/// +/// Note: we use `Relaxed` atomic operations, because we are only interested in +/// the effects of operations on a single memory location. That is, we only need +/// "modification order", and not the full-blown "happens before". +struct Cache(AtomicUsize); + +impl Cache { + const CAPACITY: u32 = (core::mem::size_of::() * 8 - 1) as u32; + const MASK: usize = (1 << Cache::CAPACITY) - 1; + const INITIALIZED_BIT: usize = 1usize << Cache::CAPACITY; + + /// Creates an uninitialized cache. + #[allow(clippy::declare_interior_mutable_const)] + const fn uninitialized() -> Self { + Cache(AtomicUsize::new(0)) + } + + /// Is the `bit` in the cache set? Returns `None` if the cache has not been initialized. + #[inline] + pub(crate) fn test(&self, bit: u32) -> Option { + let cached = self.0.load(Ordering::Relaxed); + if cached == 0 { + None + } else { + Some(test_bit(cached as u128, bit)) + } + } + + /// Initializes the cache. + #[inline] + fn initialize(&self, value: usize) -> usize { + debug_assert_eq!((value & !Cache::MASK), 0); + self.0 + .store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed); + value + } +} + +cfg_if::cfg_if! { + if #[cfg(feature = "std_detect_env_override")] { + #[inline] + fn disable_features(disable: &[u8], value: &mut Initializer) { + if let Ok(disable) = core::str::from_utf8(disable) { + for v in disable.split(" ") { + let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32)); + } + } + } + + #[inline] + fn initialize(mut value: Initializer) -> Initializer { + use core::ffi::CStr; + const RUST_STD_DETECT_UNSTABLE: &CStr = c"RUST_STD_DETECT_UNSTABLE"; + cfg_if::cfg_if! { + if #[cfg(windows)] { + use alloc::vec; + #[link(name = "kernel32")] + unsafe extern "system" { + fn GetEnvironmentVariableA(name: *const u8, buffer: *mut u8, size: u32) -> u32; + } + let len = unsafe { GetEnvironmentVariableA(RUST_STD_DETECT_UNSTABLE.as_ptr().cast::(), core::ptr::null_mut(), 0) }; + if len > 0 { + // +1 to include the null terminator. + let mut env = vec![0; len as usize + 1]; + let len = unsafe { GetEnvironmentVariableA(RUST_STD_DETECT_UNSTABLE.as_ptr().cast::(), env.as_mut_ptr(), len + 1) }; + if len > 0 { + disable_features(&env[..len as usize], &mut value); + } + } + } else { + let env = unsafe { + libc::getenv(RUST_STD_DETECT_UNSTABLE.as_ptr()) + }; + if !env.is_null() { + let len = unsafe { libc::strlen(env) }; + let env = unsafe { core::slice::from_raw_parts(env as *const u8, len) }; + disable_features(env, &mut value); + } + } + } + do_initialize(value); + value + } + } else { + #[inline] + fn initialize(value: Initializer) -> Initializer { + do_initialize(value); + value + } + } +} + +#[inline] +fn do_initialize(value: Initializer) { + CACHE[0].initialize((value.0) as usize & Cache::MASK); + CACHE[1].initialize((value.0 >> Cache::CAPACITY) as usize & Cache::MASK); + CACHE[2].initialize((value.0 >> (2 * Cache::CAPACITY)) as usize & Cache::MASK); +} + +// We only have to detect features once, and it's fairly costly, so hint to LLVM +// that it should assume that cache hits are more common than misses (which is +// the point of caching). It's possibly unfortunate that this function needs to +// reach across modules like this to call `os::detect_features`, but it produces +// the best code out of several attempted variants. +// +// The `Initializer` that the cache was initialized with is returned, so that +// the caller can call `test()` on it without having to load the value from the +// cache again. +#[cold] +fn detect_and_initialize() -> Initializer { + initialize(super::os::detect_features()) +} + +/// Tests the `bit` of the storage. If the storage has not been initialized, +/// initializes it with the result of `os::detect_features()`. +/// +/// On its first invocation, it detects the CPU features and caches them in the +/// `CACHE` global variable as an `AtomicU64`. +/// +/// It uses the `Feature` variant to index into this variable as a bitset. If +/// the bit is set, the feature is enabled, and otherwise it is disabled. +/// +/// If the feature `std_detect_env_override` is enabled looks for the env +/// variable `RUST_STD_DETECT_UNSTABLE` and uses its content to disable +/// Features that would had been otherwise detected. +#[inline] +pub(crate) fn test(bit: u32) -> bool { + let (relative_bit, idx) = if bit < Cache::CAPACITY { + (bit, 0) + } else if bit < 2 * Cache::CAPACITY { + (bit - Cache::CAPACITY, 1) + } else { + (bit - 2 * Cache::CAPACITY, 2) + }; + CACHE[idx] + .test(relative_bit) + .unwrap_or_else(|| detect_and_initialize().test(bit)) +} diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs new file mode 100644 index 00000000000..a2994fb7daa --- /dev/null +++ b/library/std_detect/src/detect/macros.rs @@ -0,0 +1,204 @@ +#[macro_export] +#[allow_internal_unstable(stdarch_internal)] +#[unstable(feature = "stdarch_internal", issue = "none")] +macro_rules! detect_feature { + ($feature:tt, $feature_lit:tt) => { + $crate::detect_feature!($feature, $feature_lit : $feature_lit) + }; + ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { + $(cfg!(target_feature = $target_feature_lit) ||)* + $crate::detect::__is_feature_detected::$feature() + }; + ($feature:tt, $feature_lit:tt, without cfg check: true) => { + $crate::detect::__is_feature_detected::$feature() + }; +} + +#[allow(unused_macros, reason = "it's used in the features! macro below")] +macro_rules! check_cfg_feature { + ($feature:tt, $feature_lit:tt) => { + check_cfg_feature!($feature, $feature_lit : $feature_lit) + }; + ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { + $(cfg!(target_feature = $target_feature_lit);)* + }; + ($feature:tt, $feature_lit:tt, without cfg check: $feature_cfg_check:literal) => { + #[allow(unexpected_cfgs, reason = $feature_lit)] + { cfg!(target_feature = $feature_lit) } + }; +} + +#[allow(unused)] +macro_rules! features { + ( + @TARGET: $target:ident; + @CFG: $cfg:meta; + @MACRO_NAME: $macro_name:ident; + @MACRO_ATTRS: $(#[$macro_attrs:meta])* + $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; $(#[$deprecate_attr:meta];)?)* + $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )* + $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; + $(without cfg check: $feature_cfg_check:tt;)? + $(implied by target_features: [$($target_feature_lit:tt),*];)? + $(#[$feature_comment:meta])*)* + ) => { + #[macro_export] + $(#[$macro_attrs])* + #[allow_internal_unstable(stdarch_internal)] + #[cfg($cfg)] + #[doc(cfg($cfg))] + macro_rules! $macro_name { + $( + ($feature_lit) => { + $crate::detect_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?) + }; + )* + $( + ($bind_feature) => { + { + $( + #[$deprecate_attr] macro_rules! deprecated_feature { {} => {}; } + deprecated_feature! {}; + )? + $crate::$macro_name!($feature_impl) + } + }; + )* + $( + ($nort_feature) => { + compile_error!( + concat!( + stringify!($nort_feature), + " feature cannot be detected at run-time" + ) + ) + }; + )* + ($t:tt,) => { + $crate::$macro_name!($t); + }; + ($t:tt) => { + compile_error!( + concat!( + concat!("unknown ", stringify!($target)), + concat!(" target feature: ", $t) + ) + ) + }; + } + + $(#[$macro_attrs])* + #[macro_export] + #[cfg(not($cfg))] + #[doc(cfg($cfg))] + macro_rules! $macro_name { + $( + ($feature_lit) => { + compile_error!( + concat!( + r#"This macro cannot be used on the current target. + You can prevent it from being used in other architectures by + guarding it behind a cfg("#, + stringify!($cfg), + ")." + ) + ) + }; + )* + $( + ($bind_feature) => { $crate::$macro_name!($feature_impl) }; + )* + $( + ($nort_feature) => { + compile_error!( + concat!( + stringify!($nort_feature), + " feature cannot be detected at run-time" + ) + ) + }; + )* + ($t:tt,) => { + $crate::$macro_name!($t); + }; + ($t:tt) => { + compile_error!( + concat!( + concat!("unknown ", stringify!($target)), + concat!(" target feature: ", $t) + ) + ) + }; + } + + #[test] + #[deny(unexpected_cfgs)] + #[deny(unfulfilled_lint_expectations)] + fn unexpected_cfgs() { + $( + check_cfg_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?); + )* + } + + /// Each variant denotes a position in a bitset for a particular feature. + /// + /// PLEASE: do not use this, it is an implementation detail subject + /// to change. + #[doc(hidden)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone)] + #[repr(u8)] + #[unstable(feature = "stdarch_internal", issue = "none")] + #[cfg($cfg)] + pub(crate) enum Feature { + $( + $(#[$feature_comment])* + $feature, + )* + + // Do not add variants after last: + _last + } + + #[cfg($cfg)] + impl Feature { + pub(crate) fn to_str(self) -> &'static str { + match self { + $(Feature::$feature => $feature_lit,)* + Feature::_last => unreachable!(), + } + } + + #[cfg(feature = "std_detect_env_override")] + pub(crate) fn from_str(s: &str) -> Result { + match s { + $($feature_lit => Ok(Feature::$feature),)* + _ => Err(()) + } + } + } + + /// Each function performs run-time feature detection for a single + /// feature. This allow us to use stability attributes on a per feature + /// basis. + /// + /// PLEASE: do not use this, it is an implementation detail subject + /// to change. + #[doc(hidden)] + #[cfg($cfg)] + #[unstable(feature = "stdarch_internal", issue = "none")] + pub mod __is_feature_detected { + $( + + /// PLEASE: do not use this, it is an implementation detail + /// subject to change. + #[inline] + #[doc(hidden)] + #[$stability_attr] + pub fn $feature() -> bool { + $crate::detect::check_for($crate::detect::Feature::$feature) + } + )* + } + }; +} diff --git a/library/std_detect/src/detect/mod.rs b/library/std_detect/src/detect/mod.rs new file mode 100644 index 00000000000..a9e9709c1f6 --- /dev/null +++ b/library/std_detect/src/detect/mod.rs @@ -0,0 +1,121 @@ +//! This module implements run-time feature detection. +//! +//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a +//! feature as a string-literal, and return a boolean indicating whether the +//! feature is enabled at run-time or not. +//! +//! These macros do two things: +//! * map the string-literal into an integer stored as a `Feature` enum, +//! * call a `os::check_for(x: Feature)` function that returns `true` if the +//! feature is enabled. +//! +//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs` +//! modules. +//! +//! The `check_for` functions are, in general, Operating System dependent. Most +//! architectures do not allow user-space programs to query the feature bits +//! due to security concerns (x86 is the big exception). These functions are +//! implemented in the `os/{target_os}.rs` modules. + +use cfg_if::cfg_if; + +#[macro_use] +mod macros; + +mod arch; + +// This module needs to be public because the `is_{arch}_feature_detected!` +// macros expand calls to items within it in user crates. +#[doc(hidden)] +#[unstable(feature = "stdarch_internal", issue = "none")] +pub use self::arch::__is_feature_detected; + +pub(crate) use self::arch::Feature; + +mod bit; +mod cache; + +cfg_if! { + if #[cfg(miri)] { + // When running under miri all target-features that are not enabled at + // compile-time are reported as disabled at run-time. + // + // For features for which `cfg(target_feature)` returns true, + // this run-time detection logic is never called. + #[path = "os/other.rs"] + mod os; + } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + // On x86/x86_64 no OS specific functionality is required. + #[path = "os/x86.rs"] + mod os; + } else if #[cfg(all(any(target_os = "linux", target_os = "android"), feature = "libc"))] { + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + #[path = "os/riscv.rs"] + mod riscv; + #[path = "os/linux/mod.rs"] + mod os; + } else if #[cfg(all(target_os = "freebsd", feature = "libc"))] { + #[cfg(target_arch = "aarch64")] + #[path = "os/aarch64.rs"] + mod aarch64; + #[path = "os/freebsd/mod.rs"] + mod os; + } else if #[cfg(all(target_os = "openbsd", target_arch = "aarch64", feature = "libc"))] { + #[allow(dead_code)] // we don't use code that calls the mrs instruction. + #[path = "os/aarch64.rs"] + mod aarch64; + #[path = "os/openbsd/aarch64.rs"] + mod os; + } else if #[cfg(all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")))] { + #[path = "os/windows/aarch64.rs"] + mod os; + } else if #[cfg(all(target_vendor = "apple", target_arch = "aarch64", feature = "libc"))] { + #[path = "os/darwin/aarch64.rs"] + mod os; + } else { + #[path = "os/other.rs"] + mod os; + } +} + +/// Performs run-time feature detection. +#[inline] +#[allow(dead_code)] +fn check_for(x: Feature) -> bool { + cache::test(x as u32) +} + +/// Returns an `Iterator` where +/// `Item.0` is the feature name, and `Item.1` is a `bool` which +/// is `true` if the feature is supported by the host and `false` otherwise. +#[unstable(feature = "stdarch_internal", issue = "none")] +pub fn features() -> impl Iterator { + cfg_if! { + if #[cfg(any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "arm64ec", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "loongarch32", + target_arch = "loongarch64", + target_arch = "s390x", + ))] { + (0_u8..Feature::_last as u8).map(|discriminant: u8| { + #[allow(bindings_with_variant_name)] // RISC-V has Feature::f + let f: Feature = unsafe { core::mem::transmute(discriminant) }; + let name: &'static str = f.to_str(); + let enabled: bool = check_for(f); + (name, enabled) + }) + } else { + None.into_iter() + } + } +} diff --git a/library/std_detect/src/detect/os/aarch64.rs b/library/std_detect/src/detect/os/aarch64.rs new file mode 100644 index 00000000000..1ff2a17e6e1 --- /dev/null +++ b/library/std_detect/src/detect/os/aarch64.rs @@ -0,0 +1,130 @@ +//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction. +//! +//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use +//! privileged system registers from userspace to check CPU feature support. +//! +//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1 +//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc. +//! Each part of the register indicates the level of support for a certain feature, e.g. +//! when ID_AA64ISAR0_EL1\[7:4\] is >= 1, AES is supported; when it's >= 2, PMULL is supported. +//! +//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb), +//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947). +//! +//! References: +//! +//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp) +//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt) +//! - [ARM documentation](https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers?lang=en) + +use crate::detect::{Feature, cache}; +use core::arch::asm; + +/// Try to read the features from the system registers. +/// +/// This will cause SIGILL if the current OS is not trapping the mrs instruction. +pub(crate) fn detect_features() -> cache::Initializer { + // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 + let aa64isar0: u64; + unsafe { + asm!( + "mrs {}, ID_AA64ISAR0_EL1", + out(reg) aa64isar0, + options(pure, nomem, preserves_flags, nostack) + ); + } + + // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1 + let aa64isar1: u64; + unsafe { + asm!( + "mrs {}, ID_AA64ISAR1_EL1", + out(reg) aa64isar1, + options(pure, nomem, preserves_flags, nostack) + ); + } + + // ID_AA64MMFR2_EL1 - AArch64 Memory Model Feature Register 2 + let aa64mmfr2: u64; + unsafe { + asm!( + "mrs {}, ID_AA64MMFR2_EL1", + out(reg) aa64mmfr2, + options(pure, nomem, preserves_flags, nostack) + ); + } + + // ID_AA64PFR0_EL1 - Processor Feature Register 0 + let aa64pfr0: u64; + unsafe { + asm!( + "mrs {}, ID_AA64PFR0_EL1", + out(reg) aa64pfr0, + options(pure, nomem, preserves_flags, nostack) + ); + } + + parse_system_registers(aa64isar0, aa64isar1, aa64mmfr2, Some(aa64pfr0)) +} + +pub(crate) fn parse_system_registers( + aa64isar0: u64, + aa64isar1: u64, + aa64mmfr2: u64, + aa64pfr0: Option, +) -> cache::Initializer { + let mut value = cache::Initializer::default(); + + let mut enable_feature = |f, enable| { + if enable { + value.set(f as u32); + } + }; + + // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 + enable_feature(Feature::pmull, bits_shift(aa64isar0, 7, 4) >= 2); + enable_feature(Feature::tme, bits_shift(aa64isar0, 27, 24) == 1); + enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 2); + enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1); + + // ID_AA64PFR0_EL1 - Processor Feature Register 0 + if let Some(aa64pfr0) = aa64pfr0 { + let fp = bits_shift(aa64pfr0, 19, 16) < 0xF; + let fphp = bits_shift(aa64pfr0, 19, 16) >= 1; + let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF; + let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1; + enable_feature(Feature::fp, fp); + enable_feature(Feature::fp16, fphp); + // SIMD support requires float support - if half-floats are + // supported, it also requires half-float support: + enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp)); + // SIMD extensions require SIMD support: + enable_feature(Feature::aes, asimd && bits_shift(aa64isar0, 7, 4) >= 2); + let sha1 = bits_shift(aa64isar0, 11, 8) >= 1; + let sha2 = bits_shift(aa64isar0, 15, 12) >= 1; + enable_feature(Feature::sha2, asimd && sha1 && sha2); + enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1); + enable_feature( + Feature::dotprod, + asimd && bits_shift(aa64isar0, 47, 44) >= 1, + ); + enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1); + } + + // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1 + // Check for either APA or API field + enable_feature(Feature::paca, bits_shift(aa64isar1, 11, 4) >= 1); + enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1); + // Check for either GPA or GPI field + enable_feature(Feature::pacg, bits_shift(aa64isar1, 31, 24) >= 1); + + // ID_AA64MMFR2_EL1 - AArch64 Memory Model Feature Register 2 + enable_feature(Feature::lse2, bits_shift(aa64mmfr2, 35, 32) >= 1); + + value +} + +#[inline] +fn bits_shift(x: u64, high: usize, low: usize) -> u64 { + (x >> low) & ((1 << (high - low + 1)) - 1) +} diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs new file mode 100644 index 00000000000..44d921689e5 --- /dev/null +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -0,0 +1,155 @@ +//! Run-time feature detection for aarch64 on Darwin (macOS/iOS/tvOS/watchOS/visionOS). +//! +//! + +use crate::detect::{Feature, cache}; +use core::ffi::CStr; + +#[inline] +fn _sysctlbyname(name: &CStr) -> bool { + use libc; + + let mut enabled: i32 = 0; + let mut enabled_len: usize = 4; + let enabled_ptr = &mut enabled as *mut i32 as *mut libc::c_void; + + let ret = unsafe { + libc::sysctlbyname( + name.as_ptr(), + enabled_ptr, + &mut enabled_len, + core::ptr::null_mut(), + 0, + ) + }; + + match ret { + 0 => enabled != 0, + _ => false, + } +} + +/// Try to read the features using sysctlbyname. +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + + let mut enable_feature = |f, enable| { + if enable { + value.set(f as u32); + } + }; + + // Armv8.0 features not using the standard identifiers + let fp = _sysctlbyname(c"hw.optional.floatingpoint"); + let asimd = _sysctlbyname(c"hw.optional.AdvSIMD"); + let crc = _sysctlbyname(c"hw.optional.armv8_crc32"); + + // Armv8 and Armv9 features using the standard identifiers + let aes = _sysctlbyname(c"hw.optional.arm.FEAT_AES"); + let bf16 = _sysctlbyname(c"hw.optional.arm.FEAT_BF16"); + let bti = _sysctlbyname(c"hw.optional.arm.FEAT_BTI"); + let cssc = _sysctlbyname(c"hw.optional.arm.FEAT_CSSC"); + let dit = _sysctlbyname(c"hw.optional.arm.FEAT_DIT"); + let dpb = _sysctlbyname(c"hw.optional.arm.FEAT_DPB"); + let dpb2 = _sysctlbyname(c"hw.optional.arm.FEAT_DPB2"); + let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd"); + let ecv = _sysctlbyname(c"hw.optional.arm.FEAT_ECV"); + let fcma = _sysctlbyname(c"hw.optional.arm.FEAT_FCMA"); + let fhm = _sysctlbyname(c"hw.optional.arm.FEAT_FHM"); + let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16"); + let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS"); + let flagm = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM"); + let flagm2 = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM2"); + let hbc = _sysctlbyname(c"hw.optional.arm.FEAT_HBC"); + let i8mm = _sysctlbyname(c"hw.optional.arm.FEAT_I8MM"); + let jsconv = _sysctlbyname(c"hw.optional.arm.FEAT_JSCVT"); + let rcpc = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC"); + let rcpc2 = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC2"); + let lse = _sysctlbyname(c"hw.optional.arm.FEAT_LSE"); + let lse2 = _sysctlbyname(c"hw.optional.arm.FEAT_LSE2"); + let pauth = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth"); + let pmull = _sysctlbyname(c"hw.optional.arm.FEAT_PMULL"); + let rdm = _sysctlbyname(c"hw.optional.arm.FEAT_RDM"); + let sb = _sysctlbyname(c"hw.optional.arm.FEAT_SB"); + let sha1 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA1"); + let sha256 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA256"); + let sha3 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA3"); + let sha512 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA512"); + let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME"); + let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2"); + let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64"); + let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64"); + let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS"); + let wfxt = _sysctlbyname(c"hw.optional.arm.FEAT_WFxT"); + + // The following features are not exposed by `is_aarch64_feature_detected`, + // but *are* reported by `sysctl`. They are here as documentation that they + // exist, and may potentially be exposed later. + /* + let afp = _sysctlbyname(c"hw.optional.arm.FEAT_AFP"); + let csv2 = _sysctlbyname(c"hw.optional.arm.FEAT_CSV2"); + let csv3 = _sysctlbyname(c"hw.optional.arm.FEAT_CSV3"); + let ebf16 = _sysctlbyname(c"hw.optional.arm.FEAT_EBF16"); + let fpac = _sysctlbyname(c"hw.optional.arm.FEAT_FPAC"); + let fpaccombine = _sysctlbyname(c"hw.optional.arm.FEAT_FPACCOMBINE"); + let pacimp = _sysctlbyname(c"hw.optional.arm.FEAT_PACIMP"); + let pauth2 = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth2"); + let rpres = _sysctlbyname(c"hw.optional.arm.FEAT_RPRES"); + let specres = _sysctlbyname(c"hw.optional.arm.FEAT_SPECRES"); + let specres2 = _sysctlbyname(c"hw.optional.arm.FEAT_SPECRES2"); + */ + + // The following "features" are reported by `sysctl` but are mandatory parts + // of SME or SME2, and so are not exposed separately by + // `is_aarch64_feature_detected`. They are here to document their + // existence, in case they're needed in the future. + /* + let sme_b16f32 = _sysctlbyname(c"hw.optional.arm.SME_B16F32"); + let sme_bi32i32 = _sysctlbyname(c"hw.optional.arm.SME_BI32I32"); + let sme_f16f32 = _sysctlbyname(c"hw.optional.arm.SME_F16F32"); + let sme_f32f32 = _sysctlbyname(c"hw.optional.arm.SME_F32F32"); + let sme_i16i32 = _sysctlbyname(c"hw.optional.arm.SME_I16I32"); + let sme_i8i32 = _sysctlbyname(c"hw.optional.arm.SME_I8I32"); + */ + + enable_feature(Feature::aes, aes && pmull); + enable_feature(Feature::asimd, asimd); + enable_feature(Feature::bf16, bf16); + enable_feature(Feature::bti, bti); + enable_feature(Feature::crc, crc); + enable_feature(Feature::cssc, cssc); + enable_feature(Feature::dit, dit); + enable_feature(Feature::dotprod, dotprod); + enable_feature(Feature::dpb, dpb); + enable_feature(Feature::dpb2, dpb2); + enable_feature(Feature::ecv, ecv); + enable_feature(Feature::fcma, fcma); + enable_feature(Feature::fhm, fhm); + enable_feature(Feature::flagm, flagm); + enable_feature(Feature::flagm2, flagm2); + enable_feature(Feature::fp, fp); + enable_feature(Feature::fp16, fp16); + enable_feature(Feature::frintts, frintts); + enable_feature(Feature::hbc, hbc); + enable_feature(Feature::i8mm, i8mm); + enable_feature(Feature::jsconv, jsconv); + enable_feature(Feature::lse, lse); + enable_feature(Feature::lse2, lse2); + enable_feature(Feature::paca, pauth); + enable_feature(Feature::pacg, pauth); + enable_feature(Feature::pmull, aes && pmull); + enable_feature(Feature::rcpc, rcpc); + enable_feature(Feature::rcpc2, rcpc2); + enable_feature(Feature::rdm, rdm); + enable_feature(Feature::sb, sb); + enable_feature(Feature::sha2, sha1 && sha256 && asimd); + enable_feature(Feature::sha3, sha512 && sha3 && asimd); + enable_feature(Feature::sme, sme); + enable_feature(Feature::sme2, sme2); + enable_feature(Feature::sme_f64f64, sme_f64f64); + enable_feature(Feature::sme_i16i64, sme_i16i64); + enable_feature(Feature::ssbs, ssbs); + enable_feature(Feature::wfxt, wfxt); + + value +} diff --git a/library/std_detect/src/detect/os/freebsd/aarch64.rs b/library/std_detect/src/detect/os/freebsd/aarch64.rs new file mode 100644 index 00000000000..ccc48f53605 --- /dev/null +++ b/library/std_detect/src/detect/os/freebsd/aarch64.rs @@ -0,0 +1,3 @@ +//! Run-time feature detection for Aarch64 on FreeBSD. + +pub(crate) use super::super::aarch64::detect_features; diff --git a/library/std_detect/src/detect/os/freebsd/arm.rs b/library/std_detect/src/detect/os/freebsd/arm.rs new file mode 100644 index 00000000000..0a15156e1bd --- /dev/null +++ b/library/std_detect/src/detect/os/freebsd/arm.rs @@ -0,0 +1,36 @@ +//! Run-time feature detection for ARM on FreeBSD + +use super::auxvec; +use crate::detect::{Feature, cache}; + +// Defined in machine/elf.h. +// https://github.com/freebsd/freebsd-src/blob/deb63adf945d446ed91a9d84124c71f15ae571d1/sys/arm/include/elf.h +const HWCAP_NEON: usize = 0x00001000; +const HWCAP2_AES: usize = 0x00000001; +const HWCAP2_PMULL: usize = 0x00000002; +const HWCAP2_SHA1: usize = 0x00000004; +const HWCAP2_SHA2: usize = 0x00000008; +const HWCAP2_CRC32: usize = 0x00000010; + +/// Try to read the features from the auxiliary vector +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, f, enable| { + if enable { + value.set(f as u32); + } + }; + + if let Ok(auxv) = auxvec::auxv() { + enable_feature(&mut value, Feature::neon, auxv.hwcap & HWCAP_NEON != 0); + enable_feature(&mut value, Feature::pmull, auxv.hwcap2 & HWCAP2_PMULL != 0); + enable_feature(&mut value, Feature::crc, auxv.hwcap2 & HWCAP2_CRC32 != 0); + enable_feature(&mut value, Feature::aes, auxv.hwcap2 & HWCAP2_AES != 0); + // SHA2 requires SHA1 & SHA2 features + let sha1 = auxv.hwcap2 & HWCAP2_SHA1 != 0; + let sha2 = auxv.hwcap2 & HWCAP2_SHA2 != 0; + enable_feature(&mut value, Feature::sha2, sha1 && sha2); + return value; + } + value +} diff --git a/library/std_detect/src/detect/os/freebsd/auxvec.rs b/library/std_detect/src/detect/os/freebsd/auxvec.rs new file mode 100644 index 00000000000..4e72bf22d76 --- /dev/null +++ b/library/std_detect/src/detect/os/freebsd/auxvec.rs @@ -0,0 +1,66 @@ +//! Parses ELF auxiliary vectors. +#![cfg_attr( + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64", + target_arch = "riscv64" + ), + allow(dead_code) +)] + +/// Cache HWCAP bitfields of the ELF Auxiliary Vector. +/// +/// If an entry cannot be read all the bits in the bitfield are set to zero. +/// This should be interpreted as all the features being disabled. +#[derive(Debug, Copy, Clone)] +pub(crate) struct AuxVec { + pub hwcap: usize, + pub hwcap2: usize, +} + +/// ELF Auxiliary Vector +/// +/// The auxiliary vector is a memory region in a running ELF program's stack +/// composed of (key: usize, value: usize) pairs. +/// +/// The keys used in the aux vector are platform dependent. For FreeBSD, they are +/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given +/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. +/// +/// Note that run-time feature detection is not invoked for features that can +/// be detected at compile-time. +/// +/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707 +pub(crate) fn auxv() -> Result { + let hwcap = archauxv(libc::AT_HWCAP); + let hwcap2 = archauxv(libc::AT_HWCAP2); + // Zero could indicate that no features were detected, but it's also used to + // indicate an error. In particular, on many platforms AT_HWCAP2 will be + // legitimately zero, since it contains the most recent feature flags. + if hwcap != 0 || hwcap2 != 0 { + return Ok(AuxVec { hwcap, hwcap2 }); + } + Err(()) +} + +/// Tries to read the `key` from the auxiliary vector. +fn archauxv(key: libc::c_int) -> usize { + const OUT_LEN: libc::c_int = core::mem::size_of::() as libc::c_int; + let mut out: libc::c_ulong = 0; + unsafe { + // elf_aux_info is available on FreeBSD 12.0+ and 11.4+: + // https://github.com/freebsd/freebsd-src/commit/0b08ae2120cdd08c20a2b806e2fcef4d0a36c470 + // https://github.com/freebsd/freebsd-src/blob/release/11.4.0/sys/sys/auxv.h + // FreeBSD 11 support in std has been removed in Rust 1.75 (https://github.com/rust-lang/rust/pull/114521), + // so we can safely use this function. + let res = libc::elf_aux_info( + key, + &mut out as *mut libc::c_ulong as *mut libc::c_void, + OUT_LEN, + ); + // If elf_aux_info fails, `out` will be left at zero (which is the proper default value). + debug_assert!(res == 0 || out == 0); + } + out as usize +} diff --git a/library/std_detect/src/detect/os/freebsd/mod.rs b/library/std_detect/src/detect/os/freebsd/mod.rs new file mode 100644 index 00000000000..ade7fb6269d --- /dev/null +++ b/library/std_detect/src/detect/os/freebsd/mod.rs @@ -0,0 +1,22 @@ +//! Run-time feature detection on FreeBSD + +mod auxvec; + +cfg_if::cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub(crate) use self::aarch64::detect_features; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub(crate) use self::arm::detect_features; + } else if #[cfg(target_arch = "powerpc64")] { + mod powerpc; + pub(crate) use self::powerpc::detect_features; + } else { + use crate::detect::cache; + /// Performs run-time feature detection. + pub(crate) fn detect_features() -> cache::Initializer { + cache::Initializer::default() + } + } +} diff --git a/library/std_detect/src/detect/os/freebsd/powerpc.rs b/library/std_detect/src/detect/os/freebsd/powerpc.rs new file mode 100644 index 00000000000..d03af68cd08 --- /dev/null +++ b/library/std_detect/src/detect/os/freebsd/powerpc.rs @@ -0,0 +1,21 @@ +//! Run-time feature detection for PowerPC on FreeBSD. + +use super::auxvec; +use crate::detect::{Feature, cache}; + +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, f, enable| { + if enable { + value.set(f as u32); + } + }; + + if let Ok(auxv) = auxvec::auxv() { + enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0); + enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0); + enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0); + return value; + } + value +} diff --git a/library/std_detect/src/detect/os/linux/aarch64.rs b/library/std_detect/src/detect/os/linux/aarch64.rs new file mode 100644 index 00000000000..22a9cefff7b --- /dev/null +++ b/library/std_detect/src/detect/os/linux/aarch64.rs @@ -0,0 +1,484 @@ +//! Run-time feature detection for Aarch64 on Linux. + +use super::auxvec; +use crate::detect::{Feature, bit, cache}; + +/// Try to read the features from the auxiliary vector. +pub(crate) fn detect_features() -> cache::Initializer { + #[cfg(target_os = "android")] + let is_exynos9810 = { + // Samsung Exynos 9810 has a bug that big and little cores have different + // ISAs. And on older Android (pre-9), the kernel incorrectly reports + // that features available only on some cores are available on all cores. + // https://reviews.llvm.org/D114523 + let mut arch = [0_u8; libc::PROP_VALUE_MAX as usize]; + let len = unsafe { + libc::__system_property_get(c"ro.arch".as_ptr(), arch.as_mut_ptr() as *mut libc::c_char) + }; + // On Exynos, ro.arch is not available on Android 12+, but it is fine + // because Android 9+ includes the fix. + len > 0 && arch.starts_with(b"exynos9810") + }; + #[cfg(not(target_os = "android"))] + let is_exynos9810 = false; + + if let Ok(auxv) = auxvec::auxv() { + let hwcap: AtHwcap = auxv.into(); + return hwcap.cache(is_exynos9810); + } + cache::Initializer::default() +} + +/// These values are part of the platform-specific [asm/hwcap.h][hwcap] . +/// +/// The names match those used for cpuinfo. +/// +/// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h +#[derive(Debug, Default, PartialEq)] +struct AtHwcap { + // AT_HWCAP + fp: bool, + asimd: bool, + // evtstrm: No LLVM support. + aes: bool, + pmull: bool, + sha1: bool, + sha2: bool, + crc32: bool, + atomics: bool, + fphp: bool, + asimdhp: bool, + // cpuid: No LLVM support. + asimdrdm: bool, + jscvt: bool, + fcma: bool, + lrcpc: bool, + dcpop: bool, + sha3: bool, + sm3: bool, + sm4: bool, + asimddp: bool, + sha512: bool, + sve: bool, + fhm: bool, + dit: bool, + uscat: bool, + ilrcpc: bool, + flagm: bool, + ssbs: bool, + sb: bool, + paca: bool, + pacg: bool, + + // AT_HWCAP2 + dcpodp: bool, + sve2: bool, + sveaes: bool, + svepmull: bool, + svebitperm: bool, + svesha3: bool, + svesm4: bool, + flagm2: bool, + frint: bool, + // svei8mm: See i8mm feature. + svef32mm: bool, + svef64mm: bool, + // svebf16: See bf16 feature. + i8mm: bool, + bf16: bool, + // dgh: No LLVM support. + rng: bool, + bti: bool, + mte: bool, + ecv: bool, + // afp: bool, + // rpres: bool, + // mte3: bool, + sme: bool, + smei16i64: bool, + smef64f64: bool, + // smei8i32: bool, + // smef16f32: bool, + // smeb16f32: bool, + // smef32f32: bool, + smefa64: bool, + wfxt: bool, + // ebf16: bool, + // sveebf16: bool, + cssc: bool, + // rprfm: bool, + sve2p1: bool, + sme2: bool, + sme2p1: bool, + // smei16i32: bool, + // smebi32i32: bool, + smeb16b16: bool, + smef16f16: bool, + mops: bool, + hbc: bool, + sveb16b16: bool, + lrcpc3: bool, + lse128: bool, + fpmr: bool, + lut: bool, + faminmax: bool, + f8cvt: bool, + f8fma: bool, + f8dp4: bool, + f8dp2: bool, + f8e4m3: bool, + f8e5m2: bool, + smelutv2: bool, + smef8f16: bool, + smef8f32: bool, + smesf8fma: bool, + smesf8dp4: bool, + smesf8dp2: bool, + // pauthlr: bool, +} + +impl From for AtHwcap { + /// Reads AtHwcap from the auxiliary vector. + fn from(auxv: auxvec::AuxVec) -> Self { + AtHwcap { + fp: bit::test(auxv.hwcap, 0), + asimd: bit::test(auxv.hwcap, 1), + // evtstrm: bit::test(auxv.hwcap, 2), + aes: bit::test(auxv.hwcap, 3), + pmull: bit::test(auxv.hwcap, 4), + sha1: bit::test(auxv.hwcap, 5), + sha2: bit::test(auxv.hwcap, 6), + crc32: bit::test(auxv.hwcap, 7), + atomics: bit::test(auxv.hwcap, 8), + fphp: bit::test(auxv.hwcap, 9), + asimdhp: bit::test(auxv.hwcap, 10), + // cpuid: bit::test(auxv.hwcap, 11), + asimdrdm: bit::test(auxv.hwcap, 12), + jscvt: bit::test(auxv.hwcap, 13), + fcma: bit::test(auxv.hwcap, 14), + lrcpc: bit::test(auxv.hwcap, 15), + dcpop: bit::test(auxv.hwcap, 16), + sha3: bit::test(auxv.hwcap, 17), + sm3: bit::test(auxv.hwcap, 18), + sm4: bit::test(auxv.hwcap, 19), + asimddp: bit::test(auxv.hwcap, 20), + sha512: bit::test(auxv.hwcap, 21), + sve: bit::test(auxv.hwcap, 22), + fhm: bit::test(auxv.hwcap, 23), + dit: bit::test(auxv.hwcap, 24), + uscat: bit::test(auxv.hwcap, 25), + ilrcpc: bit::test(auxv.hwcap, 26), + flagm: bit::test(auxv.hwcap, 27), + ssbs: bit::test(auxv.hwcap, 28), + sb: bit::test(auxv.hwcap, 29), + paca: bit::test(auxv.hwcap, 30), + pacg: bit::test(auxv.hwcap, 31), + + // AT_HWCAP2 + dcpodp: bit::test(auxv.hwcap2, 0), + sve2: bit::test(auxv.hwcap2, 1), + sveaes: bit::test(auxv.hwcap2, 2), + svepmull: bit::test(auxv.hwcap2, 3), + svebitperm: bit::test(auxv.hwcap2, 4), + svesha3: bit::test(auxv.hwcap2, 5), + svesm4: bit::test(auxv.hwcap2, 6), + flagm2: bit::test(auxv.hwcap2, 7), + frint: bit::test(auxv.hwcap2, 8), + // svei8mm: bit::test(auxv.hwcap2, 9), + svef32mm: bit::test(auxv.hwcap2, 10), + svef64mm: bit::test(auxv.hwcap2, 11), + // svebf16: bit::test(auxv.hwcap2, 12), + i8mm: bit::test(auxv.hwcap2, 13), + bf16: bit::test(auxv.hwcap2, 14), + // dgh: bit::test(auxv.hwcap2, 15), + rng: bit::test(auxv.hwcap2, 16), + bti: bit::test(auxv.hwcap2, 17), + mte: bit::test(auxv.hwcap2, 18), + ecv: bit::test(auxv.hwcap2, 19), + // afp: bit::test(auxv.hwcap2, 20), + // rpres: bit::test(auxv.hwcap2, 21), + // mte3: bit::test(auxv.hwcap2, 22), + sme: bit::test(auxv.hwcap2, 23), + smei16i64: bit::test(auxv.hwcap2, 24), + smef64f64: bit::test(auxv.hwcap2, 25), + // smei8i32: bit::test(auxv.hwcap2, 26), + // smef16f32: bit::test(auxv.hwcap2, 27), + // smeb16f32: bit::test(auxv.hwcap2, 28), + // smef32f32: bit::test(auxv.hwcap2, 29), + smefa64: bit::test(auxv.hwcap2, 30), + wfxt: bit::test(auxv.hwcap2, 31), + // ebf16: bit::test(auxv.hwcap2, 32), + // sveebf16: bit::test(auxv.hwcap2, 33), + cssc: bit::test(auxv.hwcap2, 34), + // rprfm: bit::test(auxv.hwcap2, 35), + sve2p1: bit::test(auxv.hwcap2, 36), + sme2: bit::test(auxv.hwcap2, 37), + sme2p1: bit::test(auxv.hwcap2, 38), + // smei16i32: bit::test(auxv.hwcap2, 39), + // smebi32i32: bit::test(auxv.hwcap2, 40), + smeb16b16: bit::test(auxv.hwcap2, 41), + smef16f16: bit::test(auxv.hwcap2, 42), + mops: bit::test(auxv.hwcap2, 43), + hbc: bit::test(auxv.hwcap2, 44), + sveb16b16: bit::test(auxv.hwcap2, 45), + lrcpc3: bit::test(auxv.hwcap2, 46), + lse128: bit::test(auxv.hwcap2, 47), + fpmr: bit::test(auxv.hwcap2, 48), + lut: bit::test(auxv.hwcap2, 49), + faminmax: bit::test(auxv.hwcap2, 50), + f8cvt: bit::test(auxv.hwcap2, 51), + f8fma: bit::test(auxv.hwcap2, 52), + f8dp4: bit::test(auxv.hwcap2, 53), + f8dp2: bit::test(auxv.hwcap2, 54), + f8e4m3: bit::test(auxv.hwcap2, 55), + f8e5m2: bit::test(auxv.hwcap2, 56), + smelutv2: bit::test(auxv.hwcap2, 57), + smef8f16: bit::test(auxv.hwcap2, 58), + smef8f32: bit::test(auxv.hwcap2, 59), + smesf8fma: bit::test(auxv.hwcap2, 60), + smesf8dp4: bit::test(auxv.hwcap2, 61), + smesf8dp2: bit::test(auxv.hwcap2, 62), + // pauthlr: bit::test(auxv.hwcap2, ??), + } + } +} + +impl AtHwcap { + /// Initializes the cache from the feature -bits. + /// + /// The feature dependencies here come directly from LLVM's feature definitions: + /// https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64.td + fn cache(self, is_exynos9810: bool) -> cache::Initializer { + let mut value = cache::Initializer::default(); + { + let mut enable_feature = |f, enable| { + if enable { + value.set(f as u32); + } + }; + + // Samsung Exynos 9810 has a bug that big and little cores have different + // ISAs. And on older Android (pre-9), the kernel incorrectly reports + // that features available only on some cores are available on all cores. + // So, only check features that are known to be available on exynos-m3: + // $ rustc --print cfg --target aarch64-linux-android -C target-cpu=exynos-m3 | grep target_feature + // See also https://github.com/rust-lang/stdarch/pull/1378#discussion_r1103748342. + if is_exynos9810 { + enable_feature(Feature::fp, self.fp); + enable_feature(Feature::crc, self.crc32); + // ASIMD support requires float support - if half-floats are + // supported, it also requires half-float support: + let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp); + enable_feature(Feature::asimd, asimd); + // Cryptographic extensions require ASIMD + // AES also covers FEAT_PMULL + enable_feature(Feature::aes, self.aes && self.pmull && asimd); + enable_feature(Feature::sha2, self.sha1 && self.sha2 && asimd); + return value; + } + + enable_feature(Feature::fp, self.fp); + // Half-float support requires float support + enable_feature(Feature::fp16, self.fp && self.fphp); + // FHM (fp16fml in LLVM) requires half float support + enable_feature(Feature::fhm, self.fphp && self.fhm); + enable_feature(Feature::pmull, self.pmull); + enable_feature(Feature::crc, self.crc32); + enable_feature(Feature::lse, self.atomics); + enable_feature(Feature::lse2, self.uscat); + enable_feature(Feature::lse128, self.lse128 && self.atomics); + enable_feature(Feature::rcpc, self.lrcpc); + // RCPC2 (rcpc-immo in LLVM) requires RCPC support + let rcpc2 = self.ilrcpc && self.lrcpc; + enable_feature(Feature::rcpc2, rcpc2); + enable_feature(Feature::rcpc3, self.lrcpc3 && rcpc2); + enable_feature(Feature::dit, self.dit); + enable_feature(Feature::flagm, self.flagm); + enable_feature(Feature::flagm2, self.flagm2); + enable_feature(Feature::ssbs, self.ssbs); + enable_feature(Feature::sb, self.sb); + enable_feature(Feature::paca, self.paca); + enable_feature(Feature::pacg, self.pacg); + // enable_feature(Feature::pauth_lr, self.pauthlr); + enable_feature(Feature::dpb, self.dcpop); + enable_feature(Feature::dpb2, self.dcpodp); + enable_feature(Feature::rand, self.rng); + enable_feature(Feature::bti, self.bti); + enable_feature(Feature::mte, self.mte); + // jsconv requires float support + enable_feature(Feature::jsconv, self.jscvt && self.fp); + enable_feature(Feature::rdm, self.asimdrdm); + enable_feature(Feature::dotprod, self.asimddp); + enable_feature(Feature::frintts, self.frint); + + // FEAT_I8MM & FEAT_BF16 also include optional SVE components which linux exposes + // separately. We ignore that distinction here. + enable_feature(Feature::i8mm, self.i8mm); + enable_feature(Feature::bf16, self.bf16); + + // ASIMD support requires float support - if half-floats are + // supported, it also requires half-float support: + let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp); + enable_feature(Feature::asimd, asimd); + // ASIMD extensions require ASIMD support: + enable_feature(Feature::fcma, self.fcma && asimd); + enable_feature(Feature::sve, self.sve && asimd); + + // SVE extensions require SVE & ASIMD + enable_feature(Feature::f32mm, self.svef32mm && self.sve && asimd); + enable_feature(Feature::f64mm, self.svef64mm && self.sve && asimd); + + // Cryptographic extensions require ASIMD + enable_feature(Feature::aes, self.aes && asimd); + enable_feature(Feature::sha2, self.sha1 && self.sha2 && asimd); + // SHA512/SHA3 require SHA1 & SHA256 + enable_feature( + Feature::sha3, + self.sha512 && self.sha3 && self.sha1 && self.sha2 && asimd, + ); + enable_feature(Feature::sm4, self.sm3 && self.sm4 && asimd); + + // SVE2 requires SVE + let sve2 = self.sve2 && self.sve && asimd; + enable_feature(Feature::sve2, sve2); + enable_feature(Feature::sve2p1, self.sve2p1 && sve2); + // SVE2 extensions require SVE2 and crypto features + enable_feature( + Feature::sve2_aes, + self.sveaes && self.svepmull && sve2 && self.aes, + ); + enable_feature( + Feature::sve2_sm4, + self.svesm4 && sve2 && self.sm3 && self.sm4, + ); + enable_feature( + Feature::sve2_sha3, + self.svesha3 && sve2 && self.sha512 && self.sha3 && self.sha1 && self.sha2, + ); + enable_feature(Feature::sve2_bitperm, self.svebitperm && self.sve2); + enable_feature(Feature::sve_b16b16, self.bf16 && self.sveb16b16); + enable_feature(Feature::hbc, self.hbc); + enable_feature(Feature::mops, self.mops); + enable_feature(Feature::ecv, self.ecv); + enable_feature(Feature::lut, self.lut); + enable_feature(Feature::cssc, self.cssc); + enable_feature(Feature::fpmr, self.fpmr); + enable_feature(Feature::faminmax, self.faminmax); + let fp8 = self.f8cvt && self.faminmax && self.lut && self.bf16; + enable_feature(Feature::fp8, fp8); + let fp8fma = self.f8fma && fp8; + enable_feature(Feature::fp8fma, fp8fma); + let fp8dot4 = self.f8dp4 && fp8fma; + enable_feature(Feature::fp8dot4, fp8dot4); + enable_feature(Feature::fp8dot2, self.f8dp2 && fp8dot4); + enable_feature(Feature::wfxt, self.wfxt); + let sme = self.sme && self.bf16; + enable_feature(Feature::sme, sme); + enable_feature(Feature::sme_i16i64, self.smei16i64 && sme); + enable_feature(Feature::sme_f64f64, self.smef64f64 && sme); + enable_feature(Feature::sme_fa64, self.smefa64 && sme && sve2); + let sme2 = self.sme2 && sme; + enable_feature(Feature::sme2, sme2); + enable_feature(Feature::sme2p1, self.sme2p1 && sme2); + enable_feature( + Feature::sme_b16b16, + sme2 && self.bf16 && self.sveb16b16 && self.smeb16b16, + ); + enable_feature(Feature::sme_f16f16, self.smef16f16 && sme2); + enable_feature(Feature::sme_lutv2, self.smelutv2); + let sme_f8f32 = self.smef8f32 && sme2 && fp8; + enable_feature(Feature::sme_f8f32, sme_f8f32); + enable_feature(Feature::sme_f8f16, self.smef8f16 && sme_f8f32); + let ssve_fp8fma = self.smesf8fma && sme2 && fp8; + enable_feature(Feature::ssve_fp8fma, ssve_fp8fma); + let ssve_fp8dot4 = self.smesf8dp4 && ssve_fp8fma; + enable_feature(Feature::ssve_fp8dot4, ssve_fp8dot4); + enable_feature(Feature::ssve_fp8dot2, self.smesf8dp2 && ssve_fp8dot4); + } + value + } +} + +#[cfg(target_endian = "little")] +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "std_detect_file_io")] + mod auxv_from_file { + use super::auxvec::auxv_from_file; + use super::*; + // The baseline hwcaps used in the (artificial) auxv test files. + fn baseline_hwcaps() -> AtHwcap { + AtHwcap { + fp: true, + asimd: true, + aes: true, + pmull: true, + sha1: true, + sha2: true, + crc32: true, + atomics: true, + fphp: true, + asimdhp: true, + asimdrdm: true, + lrcpc: true, + dcpop: true, + asimddp: true, + ssbs: true, + ..AtHwcap::default() + } + } + + #[test] + fn linux_empty_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); + } + #[test] + fn linux_no_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); + } + #[test] + fn linux_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!( + AtHwcap::from(v), + AtHwcap { + // Some other HWCAP bits. + paca: true, + pacg: true, + // HWCAP2-only bits. + dcpodp: true, + frint: true, + rng: true, + bti: true, + mte: true, + ..baseline_hwcaps() + } + ); + } + } +} diff --git a/library/std_detect/src/detect/os/linux/arm.rs b/library/std_detect/src/detect/os/linux/arm.rs new file mode 100644 index 00000000000..bbb173227d0 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/arm.rs @@ -0,0 +1,34 @@ +//! Run-time feature detection for ARM on Linux. + +use super::auxvec; +use crate::detect::{Feature, bit, cache}; + +/// Try to read the features from the auxiliary vector. +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, f, enable| { + if enable { + value.set(f as u32); + } + }; + + // The values are part of the platform-specific [asm/hwcap.h][hwcap] + // + // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h + if let Ok(auxv) = auxvec::auxv() { + enable_feature(&mut value, Feature::i8mm, bit::test(auxv.hwcap, 27)); + enable_feature(&mut value, Feature::dotprod, bit::test(auxv.hwcap, 24)); + enable_feature(&mut value, Feature::neon, bit::test(auxv.hwcap, 12)); + enable_feature(&mut value, Feature::pmull, bit::test(auxv.hwcap2, 1)); + enable_feature(&mut value, Feature::crc, bit::test(auxv.hwcap2, 4)); + enable_feature(&mut value, Feature::aes, bit::test(auxv.hwcap2, 0)); + // SHA2 requires SHA1 & SHA2 features + enable_feature( + &mut value, + Feature::sha2, + bit::test(auxv.hwcap2, 2) && bit::test(auxv.hwcap2, 3), + ); + return value; + } + value +} diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs new file mode 100644 index 00000000000..54f52aa7533 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -0,0 +1,341 @@ +//! Parses ELF auxiliary vectors. +#![allow(dead_code)] + +pub(crate) const AT_NULL: usize = 0; + +/// Key to access the CPU Hardware capabilities bitfield. +pub(crate) const AT_HWCAP: usize = 16; +/// Key to access the CPU Hardware capabilities 2 bitfield. +#[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", +))] +pub(crate) const AT_HWCAP2: usize = 26; + +/// Cache HWCAP bitfields of the ELF Auxiliary Vector. +/// +/// If an entry cannot be read all the bits in the bitfield are set to zero. +/// This should be interpreted as all the features being disabled. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(test, derive(PartialEq))] +pub(crate) struct AuxVec { + pub hwcap: usize, + #[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + pub hwcap2: usize, +} + +/// ELF Auxiliary Vector +/// +/// The auxiliary vector is a memory region in a running ELF program's stack +/// composed of (key: usize, value: usize) pairs. +/// +/// The keys used in the aux vector are platform dependent. For Linux, they are +/// defined in [linux/auxvec.h][auxvec_h]. The hardware capabilities of a given +/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. +/// +/// There is no perfect way of reading the auxiliary vector. +/// +/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use +/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation. +/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is +/// linked to the binary - if that is not the case the behavior is undefined. +/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will +/// try to read `/proc/self/auxv`. +/// - If that fails, this function returns an error. +/// +/// Note that run-time feature detection is not invoked for features that can +/// be detected at compile-time. +/// +/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on +/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` +/// is linked to the binary. +/// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) +/// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). +/// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) +/// use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) +/// - `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) +/// - `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) +/// have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). +/// +/// For more information about when `getauxval` is available check the great +/// [`auxv` crate documentation][auxv_docs]. +/// +/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h +/// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ +pub(crate) fn auxv() -> Result { + // Try to call a getauxval function. + if let Ok(hwcap) = getauxval(AT_HWCAP) { + // Targets with only AT_HWCAP: + #[cfg(any( + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "loongarch32", + target_arch = "loongarch64", + ))] + { + // Zero could indicate that no features were detected, but it's also used to indicate + // an error. In either case, try the fallback. + if hwcap != 0 { + return Ok(AuxVec { hwcap }); + } + } + + // Targets with AT_HWCAP and AT_HWCAP2: + #[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + { + if let Ok(hwcap2) = getauxval(AT_HWCAP2) { + // Zero could indicate that no features were detected, but it's also used to indicate + // an error. In particular, on many platforms AT_HWCAP2 will be legitimately zero, + // since it contains the most recent feature flags. Use the fallback only if no + // features were detected at all. + if hwcap != 0 || hwcap2 != 0 { + return Ok(AuxVec { hwcap, hwcap2 }); + } + } + } + + // Intentionnaly not used + let _ = hwcap; + } + + #[cfg(feature = "std_detect_file_io")] + { + // If calling getauxval fails, try to read the auxiliary vector from + // its file: + auxv_from_file("/proc/self/auxv") + } + #[cfg(not(feature = "std_detect_file_io"))] + { + Err(()) + } +} + +/// Tries to read the `key` from the auxiliary vector by calling the +/// `getauxval` function. If the function is not linked, this function return `Err`. +fn getauxval(key: usize) -> Result { + type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong; + cfg_if::cfg_if! { + if #[cfg(all( + feature = "std_detect_dlsym_getauxval", + not(all( + target_os = "linux", + any(target_env = "gnu", target_env = "musl", target_env = "ohos"), + )), + not(target_os = "android"), + ))] { + let ffi_getauxval: F = unsafe { + let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); + if ptr.is_null() { + return Err(()); + } + core::mem::transmute(ptr) + }; + } else { + let ffi_getauxval: F = libc::getauxval; + } + } + Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize }) +} + +/// Tries to read the auxiliary vector from the `file`. If this fails, this +/// function returns `Err`. +#[cfg(feature = "std_detect_file_io")] +pub(super) fn auxv_from_file(file: &str) -> Result { + let file = super::read_file(file)?; + + // See . + // + // The auxiliary vector contains at most 34 (key,value) fields: from + // `AT_MINSIGSTKSZ` to `AT_NULL`, but its number may increase. + let len = file.len(); + let mut buf = alloc::vec![0_usize; 1 + len / core::mem::size_of::()]; + unsafe { + core::ptr::copy_nonoverlapping(file.as_ptr(), buf.as_mut_ptr() as *mut u8, len); + } + + auxv_from_buf(&buf) +} + +/// Tries to interpret the `buffer` as an auxiliary vector. If that fails, this +/// function returns `Err`. +#[cfg(feature = "std_detect_file_io")] +fn auxv_from_buf(buf: &[usize]) -> Result { + // Targets with only AT_HWCAP: + #[cfg(any( + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "mips", + target_arch = "mips64", + target_arch = "loongarch32", + target_arch = "loongarch64", + ))] + { + for el in buf.chunks(2) { + match el[0] { + AT_NULL => break, + AT_HWCAP => return Ok(AuxVec { hwcap: el[1] }), + _ => (), + } + } + } + // Targets with AT_HWCAP and AT_HWCAP2: + #[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + { + let mut hwcap = None; + // For some platforms, AT_HWCAP2 was added recently, so let it default to zero. + let mut hwcap2 = 0; + for el in buf.chunks(2) { + match el[0] { + AT_NULL => break, + AT_HWCAP => hwcap = Some(el[1]), + AT_HWCAP2 => hwcap2 = el[1], + _ => (), + } + } + + if let Some(hwcap) = hwcap { + return Ok(AuxVec { hwcap, hwcap2 }); + } + } + // Suppress unused variable + let _ = buf; + Err(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + // FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv + // does not always contain the AT_HWCAP key under qemu. + #[cfg(any( + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + #[test] + fn auxv_crate() { + let v = auxv(); + if let Ok(hwcap) = getauxval(AT_HWCAP) { + let rt_hwcap = v.expect("failed to find hwcap key").hwcap; + assert_eq!(rt_hwcap, hwcap); + } + + // Targets with AT_HWCAP and AT_HWCAP2: + #[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + { + if let Ok(hwcap2) = getauxval(AT_HWCAP2) { + let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2; + assert_eq!(rt_hwcap2, hwcap2); + } + } + } + + #[test] + fn auxv_dump() { + if let Ok(auxvec) = auxv() { + println!("{:?}", auxvec); + } else { + println!("both getauxval() and reading /proc/self/auxv failed!"); + } + } + + #[cfg(feature = "std_detect_file_io")] + cfg_if::cfg_if! { + if #[cfg(target_arch = "arm")] { + #[test] + fn linux_rpi3() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + assert_eq!(v.hwcap, 4174038); + assert_eq!(v.hwcap2, 16); + } + + #[test] + fn linux_macos_vb() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv"); + println!("file: {file}"); + // The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero. + let v = auxv_from_file(file).unwrap(); + assert_eq!(v.hwcap, 126614527); + assert_eq!(v.hwcap2, 0); + } + } else if #[cfg(target_arch = "aarch64")] { + #[cfg(target_endian = "little")] + #[test] + fn linux_artificial_aarch64() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + assert_eq!(v.hwcap, 0x0123456789abcdef); + assert_eq!(v.hwcap2, 0x02468ace13579bdf); + } + #[cfg(target_endian = "little")] + #[test] + fn linux_no_hwcap2_aarch64() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + // An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP. + assert_ne!(v.hwcap, 0); + assert_eq!(v.hwcap2, 0); + } + } + } + + #[test] + #[cfg(feature = "std_detect_file_io")] + fn auxv_dump_procfs() { + if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { + println!("{:?}", auxvec); + } else { + println!("reading /proc/self/auxv failed!"); + } + } + + #[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + #[test] + #[cfg(feature = "std_detect_file_io")] + fn auxv_crate_procfs() { + if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { + assert_eq!(auxv().unwrap(), procfs_auxv); + } + } +} diff --git a/library/std_detect/src/detect/os/linux/loongarch.rs b/library/std_detect/src/detect/os/linux/loongarch.rs new file mode 100644 index 00000000000..14cc7a73183 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/loongarch.rs @@ -0,0 +1,68 @@ +//! Run-time feature detection for LoongArch on Linux. + +use super::auxvec; +use crate::detect::{Feature, bit, cache}; +use core::arch::asm; + +/// Try to read the features from the auxiliary vector. +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, feature, enable| { + if enable { + value.set(feature as u32); + } + }; + + // The values are part of the platform-specific [cpucfg] + // + // [cpucfg]: LoongArch Reference Manual Volume 1: Basic Architecture v1.1 + let cpucfg2: usize; + unsafe { + asm!( + "cpucfg {}, {}", + out(reg) cpucfg2, in(reg) 2, + options(pure, nomem, preserves_flags, nostack) + ); + } + let cpucfg3: usize; + unsafe { + asm!( + "cpucfg {}, {}", + out(reg) cpucfg3, in(reg) 3, + options(pure, nomem, preserves_flags, nostack) + ); + } + enable_feature(&mut value, Feature::frecipe, bit::test(cpucfg2, 25)); + enable_feature(&mut value, Feature::div32, bit::test(cpucfg2, 26)); + enable_feature(&mut value, Feature::lam_bh, bit::test(cpucfg2, 27)); + enable_feature(&mut value, Feature::lamcas, bit::test(cpucfg2, 28)); + enable_feature(&mut value, Feature::scq, bit::test(cpucfg2, 30)); + enable_feature(&mut value, Feature::ld_seq_sa, bit::test(cpucfg3, 23)); + + // The values are part of the platform-specific [asm/hwcap.h][hwcap] + // + // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h + if let Ok(auxv) = auxvec::auxv() { + enable_feature( + &mut value, + Feature::f, + bit::test(cpucfg2, 1) && bit::test(auxv.hwcap, 3), + ); + enable_feature( + &mut value, + Feature::d, + bit::test(cpucfg2, 2) && bit::test(auxv.hwcap, 3), + ); + enable_feature(&mut value, Feature::lsx, bit::test(auxv.hwcap, 4)); + enable_feature(&mut value, Feature::lasx, bit::test(auxv.hwcap, 5)); + enable_feature( + &mut value, + Feature::lbt, + bit::test(auxv.hwcap, 10) && bit::test(auxv.hwcap, 11) && bit::test(auxv.hwcap, 12), + ); + enable_feature(&mut value, Feature::lvz, bit::test(auxv.hwcap, 9)); + enable_feature(&mut value, Feature::ual, bit::test(auxv.hwcap, 2)); + return value; + } + value +} diff --git a/library/std_detect/src/detect/os/linux/mips.rs b/library/std_detect/src/detect/os/linux/mips.rs new file mode 100644 index 00000000000..0cfa8869887 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/mips.rs @@ -0,0 +1,23 @@ +//! Run-time feature detection for MIPS on Linux. + +use super::auxvec; +use crate::detect::{Feature, bit, cache}; + +/// Try to read the features from the auxiliary vector. +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, f, enable| { + if enable { + value.set(f as u32); + } + }; + + // The values are part of the platform-specific [asm/hwcap.h][hwcap] + // + // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/mips/include/uapi/asm/hwcap.h + if let Ok(auxv) = auxvec::auxv() { + enable_feature(&mut value, Feature::msa, bit::test(auxv.hwcap, 1)); + return value; + } + value +} diff --git a/library/std_detect/src/detect/os/linux/mod.rs b/library/std_detect/src/detect/os/linux/mod.rs new file mode 100644 index 00000000000..9accd41717b --- /dev/null +++ b/library/std_detect/src/detect/os/linux/mod.rs @@ -0,0 +1,67 @@ +//! Run-time feature detection on Linux +//! +#[cfg(feature = "std_detect_file_io")] +use alloc::vec::Vec; + +mod auxvec; + +#[cfg(feature = "std_detect_file_io")] +fn read_file(path: &str) -> Result, ()> { + let mut path = Vec::from(path.as_bytes()); + path.push(0); + + unsafe { + let file = libc::open(path.as_ptr() as *const libc::c_char, libc::O_RDONLY); + if file == -1 { + return Err(()); + } + + let mut data = Vec::new(); + loop { + data.reserve(4096); + let spare = data.spare_capacity_mut(); + match libc::read(file, spare.as_mut_ptr() as *mut _, spare.len()) { + -1 => { + libc::close(file); + return Err(()); + } + 0 => break, + n => data.set_len(data.len() + n as usize), + } + } + + libc::close(file); + Ok(data) + } +} + +cfg_if::cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub(crate) use self::aarch64::detect_features; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub(crate) use self::arm::detect_features; + } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { + mod riscv; + pub(crate) use self::riscv::detect_features; + } else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] { + mod mips; + pub(crate) use self::mips::detect_features; + } else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] { + mod powerpc; + pub(crate) use self::powerpc::detect_features; + } else if #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] { + mod loongarch; + pub(crate) use self::loongarch::detect_features; + } else if #[cfg(target_arch = "s390x")] { + mod s390x; + pub(crate) use self::s390x::detect_features; + } else { + use crate::detect::cache; + /// Performs run-time feature detection. + pub(crate) fn detect_features() -> cache::Initializer { + cache::Initializer::default() + } + } +} diff --git a/library/std_detect/src/detect/os/linux/powerpc.rs b/library/std_detect/src/detect/os/linux/powerpc.rs new file mode 100644 index 00000000000..6a4f7e715d9 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/powerpc.rs @@ -0,0 +1,35 @@ +//! Run-time feature detection for PowerPC on Linux. + +use super::auxvec; +use crate::detect::{Feature, cache}; + +/// Try to read the features from the auxiliary vector. +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, f, enable| { + if enable { + value.set(f as u32); + } + }; + + // The values are part of the platform-specific [asm/cputable.h][cputable] + // + // [cputable]: https://github.com/torvalds/linux/blob/master/arch/powerpc/include/uapi/asm/cputable.h + if let Ok(auxv) = auxvec::auxv() { + // note: the PowerPC values are the mask to do the test (instead of the + // index of the bit to test like in ARM and Aarch64) + enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0); + enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0); + let power8_features = auxv.hwcap2 & 0x80000000 != 0; + enable_feature(&mut value, Feature::power8, power8_features); + enable_feature(&mut value, Feature::power8_altivec, power8_features); + enable_feature(&mut value, Feature::power8_crypto, power8_features); + enable_feature(&mut value, Feature::power8_vector, power8_features); + let power9_features = auxv.hwcap2 & 0x00800000 != 0; + enable_feature(&mut value, Feature::power9, power9_features); + enable_feature(&mut value, Feature::power9_altivec, power9_features); + enable_feature(&mut value, Feature::power9_vector, power9_features); + return value; + } + value +} diff --git a/library/std_detect/src/detect/os/linux/riscv.rs b/library/std_detect/src/detect/os/linux/riscv.rs new file mode 100644 index 00000000000..db20538af95 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/riscv.rs @@ -0,0 +1,330 @@ +//! Run-time feature detection for RISC-V on Linux. +//! +//! On RISC-V, detection using auxv only supports single-letter extensions. +//! So, we use riscv_hwprobe that supports multi-letter extensions if available. +//! + +use core::ptr; + +use super::super::riscv::imply_features; +use super::auxvec; +use crate::detect::{Feature, bit, cache}; + +// See +// for runtime status query constants. +const PR_RISCV_V_GET_CONTROL: libc::c_int = 70; +const PR_RISCV_V_VSTATE_CTRL_ON: libc::c_int = 2; +const PR_RISCV_V_VSTATE_CTRL_CUR_MASK: libc::c_int = 3; + +// See +// for riscv_hwprobe struct and hardware probing constants. + +#[repr(C)] +struct riscv_hwprobe { + key: i64, + value: u64, +} + +impl riscv_hwprobe { + // key is overwritten to -1 if not supported by riscv_hwprobe syscall. + pub fn get(&self) -> Option { + (self.key != -1).then_some(self.value) + } +} + +#[allow(non_upper_case_globals)] +const __NR_riscv_hwprobe: libc::c_long = 258; + +const RISCV_HWPROBE_KEY_BASE_BEHAVIOR: i64 = 3; +const RISCV_HWPROBE_BASE_BEHAVIOR_IMA: u64 = 1 << 0; + +const RISCV_HWPROBE_KEY_IMA_EXT_0: i64 = 4; +const RISCV_HWPROBE_IMA_FD: u64 = 1 << 0; +const RISCV_HWPROBE_IMA_C: u64 = 1 << 1; +const RISCV_HWPROBE_IMA_V: u64 = 1 << 2; +const RISCV_HWPROBE_EXT_ZBA: u64 = 1 << 3; +const RISCV_HWPROBE_EXT_ZBB: u64 = 1 << 4; +const RISCV_HWPROBE_EXT_ZBS: u64 = 1 << 5; +const RISCV_HWPROBE_EXT_ZICBOZ: u64 = 1 << 6; +const RISCV_HWPROBE_EXT_ZBC: u64 = 1 << 7; +const RISCV_HWPROBE_EXT_ZBKB: u64 = 1 << 8; +const RISCV_HWPROBE_EXT_ZBKC: u64 = 1 << 9; +const RISCV_HWPROBE_EXT_ZBKX: u64 = 1 << 10; +const RISCV_HWPROBE_EXT_ZKND: u64 = 1 << 11; +const RISCV_HWPROBE_EXT_ZKNE: u64 = 1 << 12; +const RISCV_HWPROBE_EXT_ZKNH: u64 = 1 << 13; +const RISCV_HWPROBE_EXT_ZKSED: u64 = 1 << 14; +const RISCV_HWPROBE_EXT_ZKSH: u64 = 1 << 15; +const RISCV_HWPROBE_EXT_ZKT: u64 = 1 << 16; +const RISCV_HWPROBE_EXT_ZVBB: u64 = 1 << 17; +const RISCV_HWPROBE_EXT_ZVBC: u64 = 1 << 18; +const RISCV_HWPROBE_EXT_ZVKB: u64 = 1 << 19; +const RISCV_HWPROBE_EXT_ZVKG: u64 = 1 << 20; +const RISCV_HWPROBE_EXT_ZVKNED: u64 = 1 << 21; +const RISCV_HWPROBE_EXT_ZVKNHA: u64 = 1 << 22; +const RISCV_HWPROBE_EXT_ZVKNHB: u64 = 1 << 23; +const RISCV_HWPROBE_EXT_ZVKSED: u64 = 1 << 24; +const RISCV_HWPROBE_EXT_ZVKSH: u64 = 1 << 25; +const RISCV_HWPROBE_EXT_ZVKT: u64 = 1 << 26; +const RISCV_HWPROBE_EXT_ZFH: u64 = 1 << 27; +const RISCV_HWPROBE_EXT_ZFHMIN: u64 = 1 << 28; +const RISCV_HWPROBE_EXT_ZIHINTNTL: u64 = 1 << 29; +const RISCV_HWPROBE_EXT_ZVFH: u64 = 1 << 30; +const RISCV_HWPROBE_EXT_ZVFHMIN: u64 = 1 << 31; +const RISCV_HWPROBE_EXT_ZFA: u64 = 1 << 32; +const RISCV_HWPROBE_EXT_ZTSO: u64 = 1 << 33; +const RISCV_HWPROBE_EXT_ZACAS: u64 = 1 << 34; +const RISCV_HWPROBE_EXT_ZICOND: u64 = 1 << 35; +const RISCV_HWPROBE_EXT_ZIHINTPAUSE: u64 = 1 << 36; +const RISCV_HWPROBE_EXT_ZVE32X: u64 = 1 << 37; +const RISCV_HWPROBE_EXT_ZVE32F: u64 = 1 << 38; +const RISCV_HWPROBE_EXT_ZVE64X: u64 = 1 << 39; +const RISCV_HWPROBE_EXT_ZVE64F: u64 = 1 << 40; +const RISCV_HWPROBE_EXT_ZVE64D: u64 = 1 << 41; +const RISCV_HWPROBE_EXT_ZIMOP: u64 = 1 << 42; +const RISCV_HWPROBE_EXT_ZCA: u64 = 1 << 43; +const RISCV_HWPROBE_EXT_ZCB: u64 = 1 << 44; +const RISCV_HWPROBE_EXT_ZCD: u64 = 1 << 45; +const RISCV_HWPROBE_EXT_ZCF: u64 = 1 << 46; +const RISCV_HWPROBE_EXT_ZCMOP: u64 = 1 << 47; +const RISCV_HWPROBE_EXT_ZAWRS: u64 = 1 << 48; +// Excluded because it only reports the existence of `prctl`-based pointer masking control. +// const RISCV_HWPROBE_EXT_SUPM: u64 = 1 << 49; +const RISCV_HWPROBE_EXT_ZICNTR: u64 = 1 << 50; +const RISCV_HWPROBE_EXT_ZIHPM: u64 = 1 << 51; +const RISCV_HWPROBE_EXT_ZFBFMIN: u64 = 1 << 52; +const RISCV_HWPROBE_EXT_ZVFBFMIN: u64 = 1 << 53; +const RISCV_HWPROBE_EXT_ZVFBFWMA: u64 = 1 << 54; +const RISCV_HWPROBE_EXT_ZICBOM: u64 = 1 << 55; +const RISCV_HWPROBE_EXT_ZAAMO: u64 = 1 << 56; +const RISCV_HWPROBE_EXT_ZALRSC: u64 = 1 << 57; + +const RISCV_HWPROBE_KEY_CPUPERF_0: i64 = 5; +const RISCV_HWPROBE_MISALIGNED_FAST: u64 = 3; +const RISCV_HWPROBE_MISALIGNED_MASK: u64 = 7; + +const RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF: i64 = 9; +const RISCV_HWPROBE_MISALIGNED_SCALAR_FAST: u64 = 3; + +const RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF: i64 = 10; +const RISCV_HWPROBE_MISALIGNED_VECTOR_FAST: u64 = 3; + +// syscall returns an unsupported error if riscv_hwprobe is not supported, +// so we can safely use this function on older versions of Linux. +fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool { + unsafe fn __riscv_hwprobe( + pairs: *mut riscv_hwprobe, + pair_count: libc::size_t, + cpu_set_size: libc::size_t, + cpus: *mut libc::c_ulong, + flags: libc::c_uint, + ) -> libc::c_long { + unsafe { + libc::syscall( + __NR_riscv_hwprobe, + pairs, + pair_count, + cpu_set_size, + cpus, + flags, + ) + } + } + + unsafe { __riscv_hwprobe(out.as_mut_ptr(), out.len(), 0, ptr::null_mut(), 0) == 0 } +} + +/// Read list of supported features from (1) the auxiliary vector +/// and (2) the results of `riscv_hwprobe` and `prctl` system calls. +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + let mut enable_feature = |feature, enable| { + if enable { + value.set(feature as u32); + } + }; + + // Use auxiliary vector to enable single-letter ISA extensions. + // The values are part of the platform-specific [asm/hwcap.h][hwcap] + // + // [hwcap]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/riscv/include/uapi/asm/hwcap.h?h=v6.15 + let auxv = auxvec::auxv().expect("read auxvec"); // should not fail on RISC-V platform + let mut has_i = bit::test(auxv.hwcap, (b'i' - b'a').into()); + #[allow(clippy::eq_op)] + enable_feature(Feature::a, bit::test(auxv.hwcap, (b'a' - b'a').into())); + enable_feature(Feature::c, bit::test(auxv.hwcap, (b'c' - b'a').into())); + enable_feature(Feature::d, bit::test(auxv.hwcap, (b'd' - b'a').into())); + enable_feature(Feature::f, bit::test(auxv.hwcap, (b'f' - b'a').into())); + enable_feature(Feature::m, bit::test(auxv.hwcap, (b'm' - b'a').into())); + let has_v = bit::test(auxv.hwcap, (b'v' - b'a').into()); + let mut is_v_set = false; + + // Use riscv_hwprobe syscall to query more extensions and + // performance-related capabilities. + 'hwprobe: { + macro_rules! init { + { $($name: ident : $key: expr),* $(,)? } => { + #[repr(usize)] + enum Indices { $($name),* } + let mut t = [$(riscv_hwprobe { key: $key, value: 0 }),*]; + macro_rules! data_mut { () => { &mut t } } + macro_rules! query { [$idx: ident] => { t[Indices::$idx as usize].get() } } + } + } + init! { + BaseBehavior: RISCV_HWPROBE_KEY_BASE_BEHAVIOR, + Extensions: RISCV_HWPROBE_KEY_IMA_EXT_0, + MisalignedScalarPerf: RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF, + MisalignedVectorPerf: RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, + MisalignedScalarPerfFallback: RISCV_HWPROBE_KEY_CPUPERF_0, + }; + if !_riscv_hwprobe(data_mut!()) { + break 'hwprobe; + } + + // Query scalar misaligned behavior. + if let Some(value) = query![MisalignedScalarPerf] { + enable_feature( + Feature::unaligned_scalar_mem, + value == RISCV_HWPROBE_MISALIGNED_SCALAR_FAST, + ); + } else if let Some(value) = query![MisalignedScalarPerfFallback] { + // Deprecated method for fallback + enable_feature( + Feature::unaligned_scalar_mem, + value & RISCV_HWPROBE_MISALIGNED_MASK == RISCV_HWPROBE_MISALIGNED_FAST, + ); + } + + // Query vector misaligned behavior. + if let Some(value) = query![MisalignedVectorPerf] { + enable_feature( + Feature::unaligned_vector_mem, + value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST, + ); + } + + // Query whether "I" base and extensions "M" and "A" (as in the ISA + // manual version 2.2) are enabled. "I" base at that time corresponds + // to "I", "Zicsr", "Zicntr" and "Zifencei" (as in the ISA manual version + // 20240411). + // This is a current requirement of + // `RISCV_HWPROBE_KEY_IMA_EXT_0`-based tests. + if query![BaseBehavior].is_none_or(|value| value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA == 0) { + break 'hwprobe; + } + has_i = true; + enable_feature(Feature::zicsr, true); + enable_feature(Feature::zicntr, true); + enable_feature(Feature::zifencei, true); + enable_feature(Feature::m, true); + enable_feature(Feature::a, true); + + // Enable features based on `RISCV_HWPROBE_KEY_IMA_EXT_0`. + let Some(ima_ext_0) = query![Extensions] else { + break 'hwprobe; + }; + let test = |mask| (ima_ext_0 & mask) != 0; + + enable_feature(Feature::d, test(RISCV_HWPROBE_IMA_FD)); // F is implied. + enable_feature(Feature::c, test(RISCV_HWPROBE_IMA_C)); + + enable_feature(Feature::zicntr, test(RISCV_HWPROBE_EXT_ZICNTR)); + enable_feature(Feature::zihpm, test(RISCV_HWPROBE_EXT_ZIHPM)); + + enable_feature(Feature::zihintntl, test(RISCV_HWPROBE_EXT_ZIHINTNTL)); + enable_feature(Feature::zihintpause, test(RISCV_HWPROBE_EXT_ZIHINTPAUSE)); + enable_feature(Feature::zimop, test(RISCV_HWPROBE_EXT_ZIMOP)); + enable_feature(Feature::zicbom, test(RISCV_HWPROBE_EXT_ZICBOM)); + enable_feature(Feature::zicboz, test(RISCV_HWPROBE_EXT_ZICBOZ)); + enable_feature(Feature::zicond, test(RISCV_HWPROBE_EXT_ZICOND)); + + enable_feature(Feature::zalrsc, test(RISCV_HWPROBE_EXT_ZALRSC)); + enable_feature(Feature::zaamo, test(RISCV_HWPROBE_EXT_ZAAMO)); + enable_feature(Feature::zawrs, test(RISCV_HWPROBE_EXT_ZAWRS)); + enable_feature(Feature::zacas, test(RISCV_HWPROBE_EXT_ZACAS)); + enable_feature(Feature::ztso, test(RISCV_HWPROBE_EXT_ZTSO)); + + enable_feature(Feature::zba, test(RISCV_HWPROBE_EXT_ZBA)); + enable_feature(Feature::zbb, test(RISCV_HWPROBE_EXT_ZBB)); + enable_feature(Feature::zbs, test(RISCV_HWPROBE_EXT_ZBS)); + enable_feature(Feature::zbc, test(RISCV_HWPROBE_EXT_ZBC)); + + enable_feature(Feature::zbkb, test(RISCV_HWPROBE_EXT_ZBKB)); + enable_feature(Feature::zbkc, test(RISCV_HWPROBE_EXT_ZBKC)); + enable_feature(Feature::zbkx, test(RISCV_HWPROBE_EXT_ZBKX)); + enable_feature(Feature::zknd, test(RISCV_HWPROBE_EXT_ZKND)); + enable_feature(Feature::zkne, test(RISCV_HWPROBE_EXT_ZKNE)); + enable_feature(Feature::zknh, test(RISCV_HWPROBE_EXT_ZKNH)); + enable_feature(Feature::zksed, test(RISCV_HWPROBE_EXT_ZKSED)); + enable_feature(Feature::zksh, test(RISCV_HWPROBE_EXT_ZKSH)); + enable_feature(Feature::zkt, test(RISCV_HWPROBE_EXT_ZKT)); + + enable_feature(Feature::zcmop, test(RISCV_HWPROBE_EXT_ZCMOP)); + enable_feature(Feature::zca, test(RISCV_HWPROBE_EXT_ZCA)); + enable_feature(Feature::zcf, test(RISCV_HWPROBE_EXT_ZCF)); + enable_feature(Feature::zcd, test(RISCV_HWPROBE_EXT_ZCD)); + enable_feature(Feature::zcb, test(RISCV_HWPROBE_EXT_ZCB)); + + enable_feature(Feature::zfh, test(RISCV_HWPROBE_EXT_ZFH)); + enable_feature(Feature::zfhmin, test(RISCV_HWPROBE_EXT_ZFHMIN)); + enable_feature(Feature::zfa, test(RISCV_HWPROBE_EXT_ZFA)); + enable_feature(Feature::zfbfmin, test(RISCV_HWPROBE_EXT_ZFBFMIN)); + + // Use prctl (if any) to determine whether the vector extension + // is enabled on the current thread (assuming the entire process + // share the same status). If prctl fails (e.g. QEMU userland emulator + // as of version 9.2.3), use auxiliary vector to retrieve the default + // vector status on the process startup. + let has_vectors = { + let v_status = unsafe { libc::prctl(PR_RISCV_V_GET_CONTROL) }; + if v_status >= 0 { + (v_status & PR_RISCV_V_VSTATE_CTRL_CUR_MASK) == PR_RISCV_V_VSTATE_CTRL_ON + } else { + has_v + } + }; + if has_vectors { + enable_feature(Feature::v, test(RISCV_HWPROBE_IMA_V)); + enable_feature(Feature::zve32x, test(RISCV_HWPROBE_EXT_ZVE32X)); + enable_feature(Feature::zve32f, test(RISCV_HWPROBE_EXT_ZVE32F)); + enable_feature(Feature::zve64x, test(RISCV_HWPROBE_EXT_ZVE64X)); + enable_feature(Feature::zve64f, test(RISCV_HWPROBE_EXT_ZVE64F)); + enable_feature(Feature::zve64d, test(RISCV_HWPROBE_EXT_ZVE64D)); + + enable_feature(Feature::zvbb, test(RISCV_HWPROBE_EXT_ZVBB)); + enable_feature(Feature::zvbc, test(RISCV_HWPROBE_EXT_ZVBC)); + enable_feature(Feature::zvkb, test(RISCV_HWPROBE_EXT_ZVKB)); + enable_feature(Feature::zvkg, test(RISCV_HWPROBE_EXT_ZVKG)); + enable_feature(Feature::zvkned, test(RISCV_HWPROBE_EXT_ZVKNED)); + enable_feature(Feature::zvknha, test(RISCV_HWPROBE_EXT_ZVKNHA)); + enable_feature(Feature::zvknhb, test(RISCV_HWPROBE_EXT_ZVKNHB)); + enable_feature(Feature::zvksed, test(RISCV_HWPROBE_EXT_ZVKSED)); + enable_feature(Feature::zvksh, test(RISCV_HWPROBE_EXT_ZVKSH)); + enable_feature(Feature::zvkt, test(RISCV_HWPROBE_EXT_ZVKT)); + + enable_feature(Feature::zvfh, test(RISCV_HWPROBE_EXT_ZVFH)); + enable_feature(Feature::zvfhmin, test(RISCV_HWPROBE_EXT_ZVFHMIN)); + enable_feature(Feature::zvfbfmin, test(RISCV_HWPROBE_EXT_ZVFBFMIN)); + enable_feature(Feature::zvfbfwma, test(RISCV_HWPROBE_EXT_ZVFBFWMA)); + } + is_v_set = true; + }; + + // Set V purely depending on the auxiliary vector + // only if no fine-grained vector extension detection is available. + if !is_v_set { + enable_feature(Feature::v, has_v); + } + + // Handle base ISA. + // If future RV128I is supported, implement with `enable_feature` here. + // Note that we should use `target_arch` instead of `target_pointer_width` + // to avoid misdetection caused by experimental ABIs such as RV64ILP32. + #[cfg(target_arch = "riscv64")] + enable_feature(Feature::rv64i, has_i); + #[cfg(target_arch = "riscv32")] + enable_feature(Feature::rv32i, has_i); + + imply_features(value) +} diff --git a/library/std_detect/src/detect/os/linux/s390x.rs b/library/std_detect/src/detect/os/linux/s390x.rs new file mode 100644 index 00000000000..9b53f526d61 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/s390x.rs @@ -0,0 +1,152 @@ +//! Run-time feature detection for s390x on Linux. + +use super::auxvec; +use crate::detect::{Feature, bit, cache}; + +/// Try to read the features from the auxiliary vector +pub(crate) fn detect_features() -> cache::Initializer { + let opt_hwcap: Option = auxvec::auxv().ok().map(Into::into); + let facilities = ExtendedFacilityList::new(); + cache(opt_hwcap, facilities) +} + +#[derive(Debug, Default, PartialEq)] +struct AtHwcap { + esan3: bool, + zarch: bool, + stfle: bool, + msa: bool, + ldisp: bool, + eimm: bool, + dfp: bool, + hpage: bool, + etf3eh: bool, + high_gprs: bool, + te: bool, + vxrs: bool, + vxrs_bcd: bool, + vxrs_ext: bool, + gs: bool, + vxrs_ext2: bool, + vxrs_pde: bool, + sort: bool, + dflt: bool, + vxrs_pde2: bool, + nnpa: bool, + pci_mio: bool, + sie: bool, +} + +impl From for AtHwcap { + /// Reads AtHwcap from the auxiliary vector. + fn from(auxv: auxvec::AuxVec) -> Self { + AtHwcap { + esan3: bit::test(auxv.hwcap, 0), + zarch: bit::test(auxv.hwcap, 1), + stfle: bit::test(auxv.hwcap, 2), + msa: bit::test(auxv.hwcap, 3), + ldisp: bit::test(auxv.hwcap, 4), + eimm: bit::test(auxv.hwcap, 5), + dfp: bit::test(auxv.hwcap, 6), + hpage: bit::test(auxv.hwcap, 7), + etf3eh: bit::test(auxv.hwcap, 8), + high_gprs: bit::test(auxv.hwcap, 9), + te: bit::test(auxv.hwcap, 10), + vxrs: bit::test(auxv.hwcap, 11), + vxrs_bcd: bit::test(auxv.hwcap, 12), + vxrs_ext: bit::test(auxv.hwcap, 13), + gs: bit::test(auxv.hwcap, 14), + vxrs_ext2: bit::test(auxv.hwcap, 15), + vxrs_pde: bit::test(auxv.hwcap, 16), + sort: bit::test(auxv.hwcap, 17), + dflt: bit::test(auxv.hwcap, 18), + vxrs_pde2: bit::test(auxv.hwcap, 19), + nnpa: bit::test(auxv.hwcap, 20), + pci_mio: bit::test(auxv.hwcap, 21), + sie: bit::test(auxv.hwcap, 22), + } + } +} + +struct ExtendedFacilityList([u64; 4]); + +impl ExtendedFacilityList { + fn new() -> Self { + let mut result: [u64; 4] = [0; 4]; + // SAFETY: rust/llvm only support s390x version with the `stfle` instruction. + unsafe { + core::arch::asm!( + // equivalently ".insn s, 0xb2b00000, 0({1})", + "stfle 0({})", + in(reg_addr) result.as_mut_ptr() , + inout("r0") result.len() as u64 - 1 => _, + options(nostack) + ); + } + Self(result) + } + + const fn get_bit(&self, n: usize) -> bool { + // NOTE: bits are numbered from the left. + self.0[n / 64] & (1 << (63 - (n % 64))) != 0 + } +} + +/// Initializes the cache from the feature bits. +/// +/// These values are part of the platform-specific [asm/elf.h][kernel], and are a selection of the +/// fields found in the [Facility Indications]. +/// +/// [Facility Indications]: https://www.ibm.com/support/pages/sites/default/files/2021-05/SA22-7871-10.pdf#page=63 +/// [kernel]: https://github.com/torvalds/linux/blob/b62cef9a5c673f1b8083159f5dc03c1c5daced2f/arch/s390/include/asm/elf.h#L129 +fn cache(hwcap: Option, facilities: ExtendedFacilityList) -> cache::Initializer { + let mut value = cache::Initializer::default(); + + { + let mut enable_if_set = |bit_index, f| { + if facilities.get_bit(bit_index) { + value.set(f as u32); + } + }; + + // We use HWCAP for `vector` because it requires both hardware and kernel support. + if let Some(AtHwcap { vxrs: true, .. }) = hwcap { + // vector and related + + enable_if_set(129, Feature::vector); + + enable_if_set(135, Feature::vector_enhancements_1); + enable_if_set(148, Feature::vector_enhancements_2); + enable_if_set(198, Feature::vector_enhancements_3); + + enable_if_set(134, Feature::vector_packed_decimal); + enable_if_set(152, Feature::vector_packed_decimal_enhancement); + enable_if_set(192, Feature::vector_packed_decimal_enhancement_2); + enable_if_set(199, Feature::vector_packed_decimal_enhancement_3); + + enable_if_set(165, Feature::nnp_assist); + } + + // others + + enable_if_set(76, Feature::message_security_assist_extension3); + enable_if_set(77, Feature::message_security_assist_extension4); + enable_if_set(57, Feature::message_security_assist_extension5); + enable_if_set(146, Feature::message_security_assist_extension8); + enable_if_set(155, Feature::message_security_assist_extension9); + enable_if_set(86, Feature::message_security_assist_extension12); + + enable_if_set(58, Feature::miscellaneous_extensions_2); + enable_if_set(61, Feature::miscellaneous_extensions_3); + enable_if_set(84, Feature::miscellaneous_extensions_4); + + enable_if_set(45, Feature::high_word); + enable_if_set(73, Feature::transactional_execution); + enable_if_set(133, Feature::guarded_storage); + enable_if_set(150, Feature::enhanced_sort); + enable_if_set(151, Feature::deflate_conversion); + enable_if_set(201, Feature::concurrent_functions); + } + + value +} diff --git a/library/std_detect/src/detect/os/openbsd/aarch64.rs b/library/std_detect/src/detect/os/openbsd/aarch64.rs new file mode 100644 index 00000000000..cfe4ad10ad6 --- /dev/null +++ b/library/std_detect/src/detect/os/openbsd/aarch64.rs @@ -0,0 +1,55 @@ +//! Run-time feature detection for Aarch64 on OpenBSD. +//! +//! OpenBSD doesn't trap the mrs instruction, but exposes the system registers through sysctl. +//! https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8 +//! https://github.com/golang/go/commit/cd54ef1f61945459486e9eea2f016d99ef1da925 + +use crate::detect::cache; +use core::{mem::MaybeUninit, ptr}; + +// Defined in machine/cpu.h. +// https://github.com/openbsd/src/blob/72ccc03bd11da614f31f7ff76e3f6fce99bc1c79/sys/arch/arm64/include/cpu.h#L25-L40 +const CPU_ID_AA64ISAR0: libc::c_int = 2; +const CPU_ID_AA64ISAR1: libc::c_int = 3; +const CPU_ID_AA64MMFR2: libc::c_int = 7; +const CPU_ID_AA64PFR0: libc::c_int = 8; + +/// Try to read the features from the system registers. +pub(crate) fn detect_features() -> cache::Initializer { + // ID_AA64ISAR0_EL1 and ID_AA64ISAR1_EL1 are supported on OpenBSD 7.1+. + // https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8 + // Others are supported on OpenBSD 7.3+. + // https://github.com/openbsd/src/commit/c7654cd65262d532212f65123ee3905ba200365c + // sysctl returns an unsupported error if operation is not supported, + // so we can safely use this function on older versions of OpenBSD. + let aa64isar0 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64ISAR0]).unwrap_or(0); + let aa64isar1 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64ISAR1]).unwrap_or(0); + let aa64mmfr2 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64MMFR2]).unwrap_or(0); + // Do not use unwrap_or(0) because in fp and asimd fields, 0 indicates that + // the feature is available. + let aa64pfr0 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64PFR0]); + + super::aarch64::parse_system_registers(aa64isar0, aa64isar1, aa64mmfr2, aa64pfr0) +} + +#[inline] +fn sysctl64(mib: &[libc::c_int]) -> Option { + const OUT_LEN: libc::size_t = core::mem::size_of::(); + let mut out = MaybeUninit::::uninit(); + let mut out_len = OUT_LEN; + let res = unsafe { + libc::sysctl( + mib.as_ptr(), + mib.len() as libc::c_uint, + out.as_mut_ptr() as *mut libc::c_void, + &mut out_len, + ptr::null_mut(), + 0, + ) + }; + if res == -1 || out_len != OUT_LEN { + return None; + } + // SAFETY: we've checked that sysctl was successful and `out` was filled. + Some(unsafe { out.assume_init() }) +} diff --git a/library/std_detect/src/detect/os/other.rs b/library/std_detect/src/detect/os/other.rs new file mode 100644 index 00000000000..091fafc4ebf --- /dev/null +++ b/library/std_detect/src/detect/os/other.rs @@ -0,0 +1,8 @@ +//! Other operating systems + +use crate::detect::cache; + +#[allow(dead_code)] +pub(crate) fn detect_features() -> cache::Initializer { + cache::Initializer::default() +} diff --git a/library/std_detect/src/detect/os/riscv.rs b/library/std_detect/src/detect/os/riscv.rs new file mode 100644 index 00000000000..4c59ede8029 --- /dev/null +++ b/library/std_detect/src/detect/os/riscv.rs @@ -0,0 +1,203 @@ +//! Run-time feature detection utility for RISC-V. +//! +//! On RISC-V, full feature detection needs a help of one or more +//! feature detection mechanisms (usually provided by the operating system). +//! +//! RISC-V architecture defines many extensions and some have dependency to others. +//! More importantly, some of them cannot be enabled without resolving such +//! dependencies due to limited set of features that such mechanisms provide. +//! +//! This module provides an OS-independent utility to process such relations +//! between RISC-V extensions. + +use crate::detect::{Feature, cache}; + +/// Imply features by the given set of enabled features. +/// +/// Note that it does not perform any consistency checks including existence of +/// conflicting extensions and/or complicated requirements. Eliminating such +/// inconsistencies is the responsibility of the feature detection logic and +/// its provider(s). +pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initializer { + loop { + // Check convergence of the feature flags later. + let prev = value; + + // Expect that the optimizer turns repeated operations into + // a fewer number of bit-manipulation operations. + macro_rules! imply { + // Regular implication: + // A1 => (B1[, B2...]), A2 => (B1[, B2...]) and so on. + ($($from: ident)|+ => $($to: ident)&+) => { + if [$(Feature::$from as u32),+].iter().any(|&x| value.test(x)) { + $( + value.set(Feature::$to as u32); + )+ + } + }; + // Implication with multiple requirements: + // A1 && A2 ... => (B1[, B2...]). + ($($from: ident)&+ => $($to: ident)&+) => { + if [$(Feature::$from as u32),+].iter().all(|&x| value.test(x)) { + $( + value.set(Feature::$to as u32); + )+ + } + }; + } + macro_rules! group { + ($group: ident == $($member: ident)&+) => { + // Forward implication as defined in the specifications. + imply!($group => $($member)&+); + // Reverse implication to "group extension" from its members. + // This is not a part of specifications but convenient for + // feature detection and implemented in e.g. LLVM. + imply!($($member)&+ => $group); + }; + } + + /* + If a dependency/implication is not explicitly stated in the + specification, it is denoted as a comment as follows: + "defined as subset": + The latter extension is described as a subset of the former + (but the evidence is weak). + "functional": + The former extension is functionally a superset of the latter + (no direct references though). + */ + + imply!(zvbb => zvkb); + + // Certain set of vector cryptography extensions form a group. + group!(zvkn == zvkned & zvknhb & zvkb & zvkt); + group!(zvknc == zvkn & zvbc); + group!(zvkng == zvkn & zvkg); + group!(zvks == zvksed & zvksh & zvkb & zvkt); + group!(zvksc == zvks & zvbc); + group!(zvksg == zvks & zvkg); + + imply!(zvknhb => zvknha); // functional + + // For vector cryptography, Zvknhb and Zvbc require integer arithmetic + // with EEW=64 (Zve64x) while others not depending on them + // require EEW=32 (Zve32x). + imply!(zvknhb | zvbc => zve64x); + imply!(zvbb | zvkb | zvkg | zvkned | zvknha | zvksed | zvksh => zve32x); + + imply!(zbc => zbkc); // defined as subset + group!(zkn == zbkb & zbkc & zbkx & zkne & zknd & zknh); + group!(zks == zbkb & zbkc & zbkx & zksed & zksh); + group!(zk == zkn & zkr & zkt); + + imply!(zacas => zaamo); + group!(a == zalrsc & zaamo); + + group!(b == zba & zbb & zbs); + + imply!(zcf => zca & f); + imply!(zcd => zca & d); + imply!(zcmop | zcb => zca); + + imply!(zhinx => zhinxmin); + imply!(zdinx | zhinxmin => zfinx); + + imply!(zvfh => zvfhmin); // functional + imply!(zvfh => zve32f & zfhmin); + imply!(zvfhmin => zve32f); + imply!(zvfbfwma => zvfbfmin & zfbfmin); + imply!(zvfbfmin => zve32f); + + imply!(v => zve64d); + imply!(zve64d => zve64f & d); + imply!(zve64f => zve64x & zve32f); + imply!(zve64x => zve32x); + imply!(zve32f => zve32x & f); + + imply!(zfh => zfhmin); + imply!(q => d); + imply!(d | zfhmin | zfa => f); + imply!(zfbfmin => f); // and some of (not all) "Zfh" instructions. + + // Relatively complex implication rules from the "C" extension. + imply!(c => zca); + imply!(c & d => zcd); + #[cfg(target_arch = "riscv32")] + imply!(c & f => zcf); + + imply!(zicntr | zihpm | f | zfinx | zve32x => zicsr); + + // Loop until the feature flags converge. + if prev == value { + return value; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple_direct() { + let mut value = cache::Initializer::default(); + value.set(Feature::f as u32); + // F (and other extensions with CSRs) -> Zicsr + assert!(imply_features(value).test(Feature::zicsr as u32)); + } + + #[test] + fn simple_indirect() { + let mut value = cache::Initializer::default(); + value.set(Feature::q as u32); + // Q -> D, D -> F, F -> Zicsr + assert!(imply_features(value).test(Feature::zicsr as u32)); + } + + #[test] + fn complex_zcd() { + let mut value = cache::Initializer::default(); + // C & D -> Zcd + value.set(Feature::c as u32); + assert!(!imply_features(value).test(Feature::zcd as u32)); + value.set(Feature::d as u32); + assert!(imply_features(value).test(Feature::zcd as u32)); + } + + #[test] + fn group_simple_forward() { + let mut value = cache::Initializer::default(); + // A -> Zalrsc & Zaamo (forward implication) + value.set(Feature::a as u32); + let value = imply_features(value); + assert!(value.test(Feature::zalrsc as u32)); + assert!(value.test(Feature::zaamo as u32)); + } + + #[test] + fn group_simple_backward() { + let mut value = cache::Initializer::default(); + // Zalrsc & Zaamo -> A (reverse implication) + value.set(Feature::zalrsc as u32); + value.set(Feature::zaamo as u32); + assert!(imply_features(value).test(Feature::a as u32)); + } + + #[test] + fn group_complex_convergence() { + let mut value = cache::Initializer::default(); + // Needs 3 iterations to converge + // (and 4th iteration for convergence checking): + // 1. [Zvksc] -> Zvks & Zvbc + // 2. Zvks -> Zvksed & Zvksh & Zvkb & Zvkt + // 3a. [Zvkned] & [Zvknhb] & [Zvkb] & Zvkt -> {Zvkn} + // 3b. Zvkn & Zvbc -> {Zvknc} + value.set(Feature::zvksc as u32); + value.set(Feature::zvkned as u32); + value.set(Feature::zvknhb as u32); + value.set(Feature::zvkb as u32); + let value = imply_features(value); + assert!(value.test(Feature::zvkn as u32)); + assert!(value.test(Feature::zvknc as u32)); + } +} diff --git a/library/std_detect/src/detect/os/windows/aarch64.rs b/library/std_detect/src/detect/os/windows/aarch64.rs new file mode 100644 index 00000000000..937f9f26eed --- /dev/null +++ b/library/std_detect/src/detect/os/windows/aarch64.rs @@ -0,0 +1,125 @@ +//! Run-time feature detection for Aarch64 on Windows. + +use crate::detect::{Feature, cache}; + +/// Try to read the features using IsProcessorFeaturePresent. +pub(crate) fn detect_features() -> cache::Initializer { + type DWORD = u32; + type BOOL = i32; + + const FALSE: BOOL = 0; + // The following Microsoft documents isn't updated for aarch64. + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent + // These are defined in winnt.h of Windows SDK + const PF_ARM_VFP_32_REGISTERS_AVAILABLE: u32 = 18; + const PF_ARM_NEON_INSTRUCTIONS_AVAILABLE: u32 = 19; + const PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE: u32 = 30; + const PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE: u32 = 31; + const PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE: u32 = 34; + const PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE: u32 = 43; + const PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE: u32 = 44; + const PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE: u32 = 45; + const PF_ARM_SVE_INSTRUCTIONS_AVAILABLE: u32 = 46; + const PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE: u32 = 47; + const PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE: u32 = 48; + const PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE: u32 = 49; + const PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE: u32 = 50; + const PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE: u32 = 51; + // const PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE: u32 = 52; + // const PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE: u32 = 53; + const PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE: u32 = 54; + const PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 55; + const PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE: u32 = 56; + // const PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE: u32 = 57; + // const PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE: u32 = 58; + // const PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE: u32 = 59; + + unsafe extern "system" { + fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL; + } + + let mut value = cache::Initializer::default(); + { + let mut enable_feature = |f, enable| { + if enable { + value.set(f as u32); + } + }; + + // Some features may be supported on current CPU, + // but no way to detect it by OS API. + // Also, we require unsafe block for the extern "system" calls. + unsafe { + enable_feature( + Feature::fp, + IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::asimd, + IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::crc, + IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::lse, + IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::dotprod, + IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::jsconv, + IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::rcpc, + IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve, + IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve2, + IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve2p1, + IsProcessorFeaturePresent(PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve2_aes, + IsProcessorFeaturePresent(PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE) != FALSE + && IsProcessorFeaturePresent(PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE) + != FALSE, + ); + enable_feature( + Feature::sve2_bitperm, + IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve_b16b16, + IsProcessorFeaturePresent(PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve2_sha3, + IsProcessorFeaturePresent(PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + enable_feature( + Feature::sve2_sm4, + IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE) != FALSE, + ); + // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE means aes, sha1, sha2 and + // pmull support + let crypto = + IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != FALSE; + enable_feature(Feature::aes, crypto); + enable_feature(Feature::pmull, crypto); + enable_feature(Feature::sha2, crypto); + } + } + value +} diff --git a/library/std_detect/src/detect/os/x86.rs b/library/std_detect/src/detect/os/x86.rs new file mode 100644 index 00000000000..8565c2f85e2 --- /dev/null +++ b/library/std_detect/src/detect/os/x86.rs @@ -0,0 +1,335 @@ +//! x86 run-time feature detection is OS independent. + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +use core::mem; + +use crate::detect::{Feature, bit, cache}; + +/// Run-time feature detection on x86 works by using the CPUID instruction. +/// +/// The [CPUID Wikipedia page][wiki_cpuid] contains +/// all the information about which flags to set to query which values, and in +/// which registers these are reported. +/// +/// The definitive references are: +/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2: +/// Instruction Set Reference, A-Z][intel64_ref]. +/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and +/// System Instructions][amd64_ref]. +/// +/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID +/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf +/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf +#[allow(clippy::similar_names)] +pub(crate) fn detect_features() -> cache::Initializer { + let mut value = cache::Initializer::default(); + + if cfg!(target_env = "sgx") { + // doesn't support this because it is untrusted data + return value; + } + + // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU + // has `cpuid` support. + + // 0. EAX = 0: Basic Information: + // - EAX returns the "Highest Function Parameter", that is, the maximum + // leaf value for subsequent calls of `cpuinfo` in range [0, + // 0x8000_0000]. - The vendor ID is stored in 12 u8 ascii chars, + // returned in EBX, EDX, and ECX (in that order): + let (max_basic_leaf, vendor_id) = unsafe { + let CpuidResult { + eax: max_basic_leaf, + ebx, + ecx, + edx, + } = __cpuid(0); + let vendor_id: [[u8; 4]; 3] = [ebx.to_ne_bytes(), edx.to_ne_bytes(), ecx.to_ne_bytes()]; + let vendor_id: [u8; 12] = mem::transmute(vendor_id); + (max_basic_leaf, vendor_id) + }; + + if max_basic_leaf < 1 { + // Earlier Intel 486, CPUID not implemented + return value; + } + + // EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits"; + // Contains information about most x86 features. + let CpuidResult { + ecx: proc_info_ecx, + edx: proc_info_edx, + .. + } = unsafe { __cpuid(0x0000_0001_u32) }; + + // EAX = 7: Queries "Extended Features"; + // Contains information about bmi,bmi2, and avx2 support. + let ( + extended_features_ebx, + extended_features_ecx, + extended_features_edx, + extended_features_eax_leaf_1, + extended_features_edx_leaf_1, + ) = if max_basic_leaf >= 7 { + let CpuidResult { ebx, ecx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; + let CpuidResult { + eax: eax_1, + edx: edx_1, + .. + } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; + (ebx, ecx, edx, eax_1, edx_1) + } else { + (0, 0, 0, 0, 0) // CPUID does not support "Extended Features" + }; + + // EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported + // - EAX returns the max leaf value for extended information, that is, + // `cpuid` calls in range [0x8000_0000; u32::MAX]: + let CpuidResult { + eax: extended_max_basic_leaf, + .. + } = unsafe { __cpuid(0x8000_0000_u32) }; + + // EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature + // Bits" + let extended_proc_info_ecx = if extended_max_basic_leaf >= 1 { + let CpuidResult { ecx, .. } = unsafe { __cpuid(0x8000_0001_u32) }; + ecx + } else { + 0 + }; + + { + // borrows value till the end of this scope: + let mut enable = |r, rb, f| { + let present = bit::test(r as usize, rb); + if present { + value.set(f as u32); + } + present + }; + + enable(proc_info_ecx, 0, Feature::sse3); + enable(proc_info_ecx, 1, Feature::pclmulqdq); + enable(proc_info_ecx, 9, Feature::ssse3); + enable(proc_info_ecx, 13, Feature::cmpxchg16b); + enable(proc_info_ecx, 19, Feature::sse4_1); + enable(proc_info_ecx, 20, Feature::sse4_2); + enable(proc_info_ecx, 22, Feature::movbe); + enable(proc_info_ecx, 23, Feature::popcnt); + enable(proc_info_ecx, 25, Feature::aes); + let f16c = enable(proc_info_ecx, 29, Feature::f16c); + enable(proc_info_ecx, 30, Feature::rdrand); + enable(extended_features_ebx, 18, Feature::rdseed); + enable(extended_features_ebx, 19, Feature::adx); + enable(extended_features_ebx, 11, Feature::rtm); + enable(proc_info_edx, 4, Feature::tsc); + enable(proc_info_edx, 23, Feature::mmx); + enable(proc_info_edx, 24, Feature::fxsr); + enable(proc_info_edx, 25, Feature::sse); + enable(proc_info_edx, 26, Feature::sse2); + enable(extended_features_ebx, 29, Feature::sha); + + enable(extended_features_ecx, 8, Feature::gfni); + enable(extended_features_ecx, 9, Feature::vaes); + enable(extended_features_ecx, 10, Feature::vpclmulqdq); + + enable(extended_features_ebx, 3, Feature::bmi1); + enable(extended_features_ebx, 8, Feature::bmi2); + + enable(extended_features_ebx, 9, Feature::ermsb); + + enable(extended_features_eax_leaf_1, 31, Feature::movrs); + + // Detect if CPUID.19h available + if bit::test(extended_features_ecx as usize, 23) { + let CpuidResult { ebx, .. } = unsafe { __cpuid(0x19) }; + enable(ebx, 0, Feature::kl); + enable(ebx, 2, Feature::widekl); + } + + // `XSAVE` and `AVX` support: + let cpu_xsave = bit::test(proc_info_ecx as usize, 26); + if cpu_xsave { + // 0. Here the CPU supports `XSAVE`. + + // 1. Detect `OSXSAVE`, that is, whether the OS is AVX enabled and + // supports saving the state of the AVX/AVX2 vector registers on + // context-switches, see: + // + // - [intel: is avx enabled?][is_avx_enabled], + // - [mozilla: sse.cpp][mozilla_sse_cpp]. + // + // [is_avx_enabled]: https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled + // [mozilla_sse_cpp]: https://hg.mozilla.org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190 + let cpu_osxsave = bit::test(proc_info_ecx as usize, 27); + + if cpu_osxsave { + // 2. The OS must have signaled the CPU that it supports saving and + // restoring the: + // + // * SSE -> `XCR0.SSE[1]` + // * AVX -> `XCR0.AVX[2]` + // * AVX-512 -> `XCR0.AVX-512[7:5]`. + // * AMX -> `XCR0.AMX[18:17]` + // + // by setting the corresponding bits of `XCR0` to `1`. + // + // This is safe because the CPU supports `xsave` + // and the OS has set `osxsave`. + let xcr0 = unsafe { _xgetbv(0) }; + // Test `XCR0.SSE[1]` and `XCR0.AVX[2]` with the mask `0b110 == 6`: + let os_avx_support = xcr0 & 6 == 6; + // Test `XCR0.AVX-512[7:5]` with the mask `0b1110_0000 == 0xe0`: + let os_avx512_support = xcr0 & 0xe0 == 0xe0; + // Test `XCR0.AMX[18:17]` with the mask `0b110_0000_0000_0000_0000 == 0x60000` + let os_amx_support = xcr0 & 0x60000 == 0x60000; + + // Only if the OS and the CPU support saving/restoring the AVX + // registers we enable `xsave` support: + if os_avx_support { + // See "13.3 ENABLING THE XSAVE FEATURE SET AND XSAVE-ENABLED + // FEATURES" in the "Intel® 64 and IA-32 Architectures Software + // Developer’s Manual, Volume 1: Basic Architecture": + // + // "Software enables the XSAVE feature set by setting + // CR4.OSXSAVE[bit 18] to 1 (e.g., with the MOV to CR4 + // instruction). If this bit is 0, execution of any of XGETBV, + // XRSTOR, XRSTORS, XSAVE, XSAVEC, XSAVEOPT, XSAVES, and XSETBV + // causes an invalid-opcode exception (#UD)" + // + enable(proc_info_ecx, 26, Feature::xsave); + + // For `xsaveopt`, `xsavec`, and `xsaves` we need to query: + // Processor Extended State Enumeration Sub-leaf (EAX = 0DH, + // ECX = 1): + if max_basic_leaf >= 0xd { + let CpuidResult { + eax: proc_extended_state1_eax, + .. + } = unsafe { __cpuid_count(0xd_u32, 1) }; + enable(proc_extended_state1_eax, 0, Feature::xsaveopt); + enable(proc_extended_state1_eax, 1, Feature::xsavec); + enable(proc_extended_state1_eax, 3, Feature::xsaves); + } + + // FMA (uses 256-bit wide registers): + let fma = enable(proc_info_ecx, 12, Feature::fma); + + // And AVX/AVX2: + enable(proc_info_ecx, 28, Feature::avx); + enable(extended_features_ebx, 5, Feature::avx2); + + // "Short" versions of AVX512 instructions + enable(extended_features_eax_leaf_1, 4, Feature::avxvnni); + enable(extended_features_eax_leaf_1, 23, Feature::avxifma); + enable(extended_features_edx_leaf_1, 4, Feature::avxvnniint8); + enable(extended_features_edx_leaf_1, 5, Feature::avxneconvert); + enable(extended_features_edx_leaf_1, 10, Feature::avxvnniint16); + + enable(extended_features_eax_leaf_1, 0, Feature::sha512); + enable(extended_features_eax_leaf_1, 1, Feature::sm3); + enable(extended_features_eax_leaf_1, 2, Feature::sm4); + + // For AVX-512 the OS also needs to support saving/restoring + // the extended state, only then we enable AVX-512 support: + // Also, Rust makes `avx512f` imply `fma` and `f16c`, because + // otherwise the assembler is broken. But Intel doesn't guarantee + // that `fma` and `f16c` are available with `avx512f`, so we + // need to check for them separately. + if os_avx512_support && f16c && fma { + enable(extended_features_ebx, 16, Feature::avx512f); + enable(extended_features_ebx, 17, Feature::avx512dq); + enable(extended_features_ebx, 21, Feature::avx512ifma); + enable(extended_features_ebx, 26, Feature::avx512pf); + enable(extended_features_ebx, 27, Feature::avx512er); + enable(extended_features_ebx, 28, Feature::avx512cd); + enable(extended_features_ebx, 30, Feature::avx512bw); + enable(extended_features_ebx, 31, Feature::avx512vl); + enable(extended_features_ecx, 1, Feature::avx512vbmi); + enable(extended_features_ecx, 6, Feature::avx512vbmi2); + enable(extended_features_ecx, 11, Feature::avx512vnni); + enable(extended_features_ecx, 12, Feature::avx512bitalg); + enable(extended_features_ecx, 14, Feature::avx512vpopcntdq); + enable(extended_features_edx, 8, Feature::avx512vp2intersect); + enable(extended_features_edx, 23, Feature::avx512fp16); + enable(extended_features_eax_leaf_1, 5, Feature::avx512bf16); + } + } + + if os_amx_support { + enable(extended_features_edx, 24, Feature::amx_tile); + enable(extended_features_edx, 25, Feature::amx_int8); + enable(extended_features_edx, 22, Feature::amx_bf16); + enable(extended_features_eax_leaf_1, 21, Feature::amx_fp16); + enable(extended_features_edx_leaf_1, 8, Feature::amx_complex); + + if max_basic_leaf >= 0x1e { + let CpuidResult { + eax: amx_feature_flags_eax, + .. + } = unsafe { __cpuid_count(0x1e_u32, 1) }; + + enable(amx_feature_flags_eax, 4, Feature::amx_fp8); + enable(amx_feature_flags_eax, 5, Feature::amx_transpose); + enable(amx_feature_flags_eax, 6, Feature::amx_tf32); + enable(amx_feature_flags_eax, 7, Feature::amx_avx512); + enable(amx_feature_flags_eax, 8, Feature::amx_movrs); + } + } + } + } + + // This detects ABM on AMD CPUs and LZCNT on Intel CPUs. + // On intel CPUs with popcnt, lzcnt implements the + // "missing part" of ABM, so we map both to the same + // internal feature. + // + // The `is_x86_feature_detected!("lzcnt")` macro then + // internally maps to Feature::abm. + enable(extended_proc_info_ecx, 5, Feature::lzcnt); + + // As Hygon Dhyana originates from AMD technology and shares most of the architecture with + // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series + // number(Family 18h). + // + // For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD + // family 17h. + // + // Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf. + // Related Hygon kernel patch can be found on + // http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn + if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" { + // These features are available on AMD arch CPUs: + enable(extended_proc_info_ecx, 6, Feature::sse4a); + enable(extended_proc_info_ecx, 21, Feature::tbm); + enable(extended_proc_info_ecx, 11, Feature::xop); + } + } + + // Unfortunately, some Skylake chips erroneously report support for BMI1 and + // BMI2 without actual support. These chips don't support AVX, and it seems + // that all Intel chips with non-erroneous support BMI do (I didn't check + // other vendors), so we can disable these flags for chips that don't also + // report support for AVX. + // + // It's possible this will pessimize future chips that do support BMI and + // not AVX, but this seems minor compared to a hard crash you get when + // executing an unsupported instruction (to put it another way, it's safe + // for us to under-report CPU features, but not to over-report them). Still, + // to limit any impact this may have in the future, we only do this for + // Intel chips, as it's a bug only present in their chips. + // + // This bug is documented as `SKL052` in the errata section of this document: + // http://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/desktop-6th-gen-core-family-spec-update.pdf + if vendor_id == *b"GenuineIntel" && !value.test(Feature::avx as u32) { + value.unset(Feature::bmi1 as u32); + value.unset(Feature::bmi2 as u32); + } + + value +} diff --git a/library/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv b/library/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv new file mode 100644 index 00000000000..ec826afcf38 Binary files /dev/null and b/library/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv differ diff --git a/library/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv b/library/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv new file mode 100644 index 00000000000..95537b73f20 Binary files /dev/null and b/library/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv differ diff --git a/library/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv b/library/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv new file mode 100644 index 00000000000..1d87264b221 Binary files /dev/null and b/library/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv differ diff --git a/library/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv b/library/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv new file mode 100644 index 00000000000..35f01cc767c Binary files /dev/null and b/library/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv differ diff --git a/library/std_detect/src/detect/test_data/linux-rpi3.auxv b/library/std_detect/src/detect/test_data/linux-rpi3.auxv new file mode 100644 index 00000000000..0538e661f63 Binary files /dev/null and b/library/std_detect/src/detect/test_data/linux-rpi3.auxv differ diff --git a/library/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv b/library/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv new file mode 100644 index 00000000000..75abc02d178 Binary files /dev/null and b/library/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv differ diff --git a/library/std_detect/src/lib.rs b/library/std_detect/src/lib.rs new file mode 100644 index 00000000000..ab1b77bad5b --- /dev/null +++ b/library/std_detect/src/lib.rs @@ -0,0 +1,36 @@ +//! Run-time feature detection for the Rust standard library. +//! +//! To detect whether a feature is enabled in the system running the binary +//! use one of the appropriate macro for the target: +//! +//! * `x86` and `x86_64`: [`is_x86_feature_detected`] +//! * `arm`: [`is_arm_feature_detected`] +//! * `aarch64`: [`is_aarch64_feature_detected`] +//! * `riscv`: [`is_riscv_feature_detected`] +//! * `mips`: [`is_mips_feature_detected`] +//! * `mips64`: [`is_mips64_feature_detected`] +//! * `powerpc`: [`is_powerpc_feature_detected`] +//! * `powerpc64`: [`is_powerpc64_feature_detected`] +//! * `loongarch`: [`is_loongarch_feature_detected`] +//! * `s390x`: [`is_s390x_feature_detected`] + +#![unstable(feature = "stdarch_internal", issue = "none")] +#![feature(staged_api, doc_cfg, allow_internal_unstable)] +#![deny(rust_2018_idioms)] +#![allow(clippy::shadow_reuse)] +#![cfg_attr(test, allow(unused_imports))] +#![no_std] +#![allow(internal_features)] + +#[cfg(test)] +#[macro_use] +extern crate std; + +// rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare> +#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))] +#[cfg(feature = "std_detect_file_io")] +extern crate alloc; + +#[doc(hidden)] +#[unstable(feature = "stdarch_internal", issue = "none")] +pub mod detect; diff --git a/library/std_detect/tests/cpu-detection.rs b/library/std_detect/tests/cpu-detection.rs new file mode 100644 index 00000000000..7976aedc758 --- /dev/null +++ b/library/std_detect/tests/cpu-detection.rs @@ -0,0 +1,354 @@ +#![allow(internal_features)] +#![feature(stdarch_internal)] +#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))] +#![cfg_attr( + any(target_arch = "aarch64", target_arch = "arm64ec"), + feature(stdarch_aarch64_feature_detection) +)] +#![cfg_attr( + any(target_arch = "riscv32", target_arch = "riscv64"), + feature(stdarch_riscv_feature_detection) +)] +#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))] +#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))] +#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))] +#![allow(clippy::unwrap_used, clippy::use_debug, clippy::print_stdout)] + +#[cfg_attr( + any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "arm64ec", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ), + macro_use +)] +extern crate std_detect; + +#[test] +fn all() { + for (f, e) in std_detect::detect::features() { + println!("{f}: {e}"); + } +} + +#[test] +#[cfg(all(target_arch = "arm", target_os = "freebsd"))] +fn arm_freebsd() { + println!("neon: {}", is_arm_feature_detected!("neon")); + println!("pmull: {}", is_arm_feature_detected!("pmull")); + println!("crc: {}", is_arm_feature_detected!("crc")); + println!("aes: {}", is_arm_feature_detected!("aes")); + println!("sha2: {}", is_arm_feature_detected!("sha2")); +} + +#[test] +#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))] +fn arm_linux() { + println!("neon: {}", is_arm_feature_detected!("neon")); + println!("pmull: {}", is_arm_feature_detected!("pmull")); + println!("crc: {}", is_arm_feature_detected!("crc")); + println!("aes: {}", is_arm_feature_detected!("aes")); + println!("sha2: {}", is_arm_feature_detected!("sha2")); + println!("dotprod: {}", is_arm_feature_detected!("dotprod")); + println!("i8mm: {}", is_arm_feature_detected!("i8mm")); +} + +#[test] +#[cfg(all( + target_arch = "aarch64", + any(target_os = "linux", target_os = "android") +))] +fn aarch64_linux() { + println!("asimd: {}", is_aarch64_feature_detected!("asimd")); + println!("neon: {}", is_aarch64_feature_detected!("neon")); + println!("pmull: {}", is_aarch64_feature_detected!("pmull")); + println!("fp: {}", is_aarch64_feature_detected!("fp")); + println!("fp16: {}", is_aarch64_feature_detected!("fp16")); + println!("sve: {}", is_aarch64_feature_detected!("sve")); + println!("crc: {}", is_aarch64_feature_detected!("crc")); + println!("lse: {}", is_aarch64_feature_detected!("lse")); + println!("lse2: {}", is_aarch64_feature_detected!("lse2")); + println!("lse128: {}", is_aarch64_feature_detected!("lse128")); + println!("rdm: {}", is_aarch64_feature_detected!("rdm")); + println!("rcpc: {}", is_aarch64_feature_detected!("rcpc")); + println!("rcpc2: {}", is_aarch64_feature_detected!("rcpc2")); + println!("rcpc3: {}", is_aarch64_feature_detected!("rcpc3")); + println!("dotprod: {}", is_aarch64_feature_detected!("dotprod")); + println!("tme: {}", is_aarch64_feature_detected!("tme")); + println!("fhm: {}", is_aarch64_feature_detected!("fhm")); + println!("dit: {}", is_aarch64_feature_detected!("dit")); + println!("flagm: {}", is_aarch64_feature_detected!("flagm")); + println!("flagm2: {}", is_aarch64_feature_detected!("flagm2")); + println!("ssbs: {}", is_aarch64_feature_detected!("ssbs")); + println!("sb: {}", is_aarch64_feature_detected!("sb")); + println!("paca: {}", is_aarch64_feature_detected!("paca")); + println!("pacg: {}", is_aarch64_feature_detected!("pacg")); + // println!("pauth-lr: {}", is_aarch64_feature_detected!("pauth-lr")); + println!("dpb: {}", is_aarch64_feature_detected!("dpb")); + println!("dpb2: {}", is_aarch64_feature_detected!("dpb2")); + println!("sve-b16b16: {}", is_aarch64_feature_detected!("sve-b16b16")); + println!("sve2: {}", is_aarch64_feature_detected!("sve2")); + println!("sve2p1: {}", is_aarch64_feature_detected!("sve2p1")); + println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes")); + println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4")); + println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3")); + println!( + "sve2-bitperm: {}", + is_aarch64_feature_detected!("sve2-bitperm") + ); + println!("frintts: {}", is_aarch64_feature_detected!("frintts")); + println!("i8mm: {}", is_aarch64_feature_detected!("i8mm")); + println!("f32mm: {}", is_aarch64_feature_detected!("f32mm")); + println!("f64mm: {}", is_aarch64_feature_detected!("f64mm")); + println!("bf16: {}", is_aarch64_feature_detected!("bf16")); + println!("rand: {}", is_aarch64_feature_detected!("rand")); + println!("bti: {}", is_aarch64_feature_detected!("bti")); + println!("mte: {}", is_aarch64_feature_detected!("mte")); + println!("jsconv: {}", is_aarch64_feature_detected!("jsconv")); + println!("fcma: {}", is_aarch64_feature_detected!("fcma")); + println!("aes: {}", is_aarch64_feature_detected!("aes")); + println!("sha2: {}", is_aarch64_feature_detected!("sha2")); + println!("sha3: {}", is_aarch64_feature_detected!("sha3")); + println!("sm4: {}", is_aarch64_feature_detected!("sm4")); + println!("hbc: {}", is_aarch64_feature_detected!("hbc")); + println!("mops: {}", is_aarch64_feature_detected!("mops")); + println!("ecv: {}", is_aarch64_feature_detected!("ecv")); + println!("cssc: {}", is_aarch64_feature_detected!("cssc")); + println!("fpmr: {}", is_aarch64_feature_detected!("fpmr")); + println!("lut: {}", is_aarch64_feature_detected!("lut")); + println!("faminmax: {}", is_aarch64_feature_detected!("faminmax")); + println!("fp8: {}", is_aarch64_feature_detected!("fp8")); + println!("fp8fma: {}", is_aarch64_feature_detected!("fp8fma")); + println!("fp8dot4: {}", is_aarch64_feature_detected!("fp8dot4")); + println!("fp8dot2: {}", is_aarch64_feature_detected!("fp8dot2")); + println!("wfxt: {}", is_aarch64_feature_detected!("wfxt")); + println!("sme: {}", is_aarch64_feature_detected!("sme")); + println!("sme-b16b16: {}", is_aarch64_feature_detected!("sme-b16b16")); + println!("sme-i16i64: {}", is_aarch64_feature_detected!("sme-i16i64")); + println!("sme-f64f64: {}", is_aarch64_feature_detected!("sme-f64f64")); + println!("sme-fa64: {}", is_aarch64_feature_detected!("sme-fa64")); + println!("sme2: {}", is_aarch64_feature_detected!("sme2")); + println!("sme2p1: {}", is_aarch64_feature_detected!("sme2p1")); + println!("sme-f16f16: {}", is_aarch64_feature_detected!("sme-f16f16")); + println!("sme-lutv2: {}", is_aarch64_feature_detected!("sme-lutv2")); + println!("sme-f8f16: {}", is_aarch64_feature_detected!("sme-f8f16")); + println!("sme-f8f32: {}", is_aarch64_feature_detected!("sme-f8f32")); + println!( + "ssve-fp8fma: {}", + is_aarch64_feature_detected!("ssve-fp8fma") + ); + println!( + "ssve-fp8dot4: {}", + is_aarch64_feature_detected!("ssve-fp8dot4") + ); + println!( + "ssve-fp8dot2: {}", + is_aarch64_feature_detected!("ssve-fp8dot2") + ); +} + +#[test] +#[cfg(all( + any(target_arch = "aarch64", target_arch = "arm64ec"), + target_os = "windows" +))] +fn aarch64_windows() { + println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); + println!("fp: {:?}", is_aarch64_feature_detected!("fp")); + println!("crc: {:?}", is_aarch64_feature_detected!("crc")); + println!("lse: {:?}", is_aarch64_feature_detected!("lse")); + println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); + println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv")); + println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); + println!("aes: {:?}", is_aarch64_feature_detected!("aes")); + println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); + println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); +} + +#[test] +#[cfg(all( + target_arch = "aarch64", + any(target_os = "freebsd", target_os = "openbsd") +))] +fn aarch64_bsd() { + println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); + println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); + println!("fp: {:?}", is_aarch64_feature_detected!("fp")); + println!("fp16: {:?}", is_aarch64_feature_detected!("fp16")); + println!("sve: {:?}", is_aarch64_feature_detected!("sve")); + println!("crc: {:?}", is_aarch64_feature_detected!("crc")); + println!("lse: {:?}", is_aarch64_feature_detected!("lse")); + println!("lse2: {:?}", is_aarch64_feature_detected!("lse2")); + println!("rdm: {:?}", is_aarch64_feature_detected!("rdm")); + println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); + println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); + println!("tme: {:?}", is_aarch64_feature_detected!("tme")); + println!("paca: {:?}", is_aarch64_feature_detected!("paca")); + println!("pacg: {:?}", is_aarch64_feature_detected!("pacg")); + println!("aes: {:?}", is_aarch64_feature_detected!("aes")); + println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); +} + +#[test] +#[cfg(all(target_arch = "aarch64", target_vendor = "apple"))] +fn aarch64_darwin() { + println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); + println!("fp: {:?}", is_aarch64_feature_detected!("fp")); + println!("fp16: {:?}", is_aarch64_feature_detected!("fp16")); + println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); + println!("crc: {:?}", is_aarch64_feature_detected!("crc")); + println!("lse: {:?}", is_aarch64_feature_detected!("lse")); + println!("lse2: {:?}", is_aarch64_feature_detected!("lse2")); + println!("rdm: {:?}", is_aarch64_feature_detected!("rdm")); + println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); + println!("rcpc2: {:?}", is_aarch64_feature_detected!("rcpc2")); + println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); + println!("fhm: {:?}", is_aarch64_feature_detected!("fhm")); + println!("flagm: {:?}", is_aarch64_feature_detected!("flagm")); + println!("ssbs: {:?}", is_aarch64_feature_detected!("ssbs")); + println!("sb: {:?}", is_aarch64_feature_detected!("sb")); + println!("paca: {:?}", is_aarch64_feature_detected!("paca")); + println!("dpb: {:?}", is_aarch64_feature_detected!("dpb")); + println!("dpb2: {:?}", is_aarch64_feature_detected!("dpb2")); + println!("frintts: {:?}", is_aarch64_feature_detected!("frintts")); + println!("i8mm: {:?}", is_aarch64_feature_detected!("i8mm")); + println!("bf16: {:?}", is_aarch64_feature_detected!("bf16")); + println!("bti: {:?}", is_aarch64_feature_detected!("bti")); + println!("fcma: {:?}", is_aarch64_feature_detected!("fcma")); + println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv")); + println!("aes: {:?}", is_aarch64_feature_detected!("aes")); + println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); + println!("sha3: {:?}", is_aarch64_feature_detected!("sha3")); +} + +#[test] +#[cfg(all( + any(target_arch = "riscv32", target_arch = "riscv64"), + any(target_os = "linux", target_os = "android") +))] +fn riscv_linux() { + println!("rv32i: {}", is_riscv_feature_detected!("rv32i")); + println!("rv32e: {}", is_riscv_feature_detected!("rv32e")); + println!("rv64i: {}", is_riscv_feature_detected!("rv64i")); + println!("rv128i: {}", is_riscv_feature_detected!("rv128i")); + println!( + "unaligned-scalar-mem: {}", + is_riscv_feature_detected!("unaligned-scalar-mem") + ); + println!( + "unaligned-vector-mem: {}", + is_riscv_feature_detected!("unaligned-vector-mem") + ); + println!("zicsr: {}", is_riscv_feature_detected!("zicsr")); + println!("zicntr: {}", is_riscv_feature_detected!("zicntr")); + println!("zihpm: {}", is_riscv_feature_detected!("zihpm")); + println!("zifencei: {}", is_riscv_feature_detected!("zifencei")); + println!("zihintntl: {}", is_riscv_feature_detected!("zihintntl")); + println!("zihintpause: {}", is_riscv_feature_detected!("zihintpause")); + println!("zimop: {}", is_riscv_feature_detected!("zimop")); + println!("zicbom: {}", is_riscv_feature_detected!("zicbom")); + println!("zicboz: {}", is_riscv_feature_detected!("zicboz")); + println!("zicond: {}", is_riscv_feature_detected!("zicond")); + println!("m: {}", is_riscv_feature_detected!("m")); + println!("a: {}", is_riscv_feature_detected!("a")); + println!("zalrsc: {}", is_riscv_feature_detected!("zalrsc")); + println!("zaamo: {}", is_riscv_feature_detected!("zaamo")); + println!("zawrs: {}", is_riscv_feature_detected!("zawrs")); + println!("zacas: {}", is_riscv_feature_detected!("zacas")); + println!("zam: {}", is_riscv_feature_detected!("zam")); + println!("ztso: {}", is_riscv_feature_detected!("ztso")); + println!("f: {}", is_riscv_feature_detected!("f")); + println!("d: {}", is_riscv_feature_detected!("d")); + println!("q: {}", is_riscv_feature_detected!("q")); + println!("zfh: {}", is_riscv_feature_detected!("zfh")); + println!("zfhmin: {}", is_riscv_feature_detected!("zfhmin")); + println!("zfa: {}", is_riscv_feature_detected!("zfa")); + println!("zfbfmin: {}", is_riscv_feature_detected!("zfbfmin")); + println!("zfinx: {}", is_riscv_feature_detected!("zfinx")); + println!("zdinx: {}", is_riscv_feature_detected!("zdinx")); + println!("zhinx: {}", is_riscv_feature_detected!("zhinx")); + println!("zhinxmin: {}", is_riscv_feature_detected!("zhinxmin")); + println!("c: {}", is_riscv_feature_detected!("c")); + println!("zca: {}", is_riscv_feature_detected!("zca")); + println!("zcf: {}", is_riscv_feature_detected!("zcf")); + println!("zcd: {}", is_riscv_feature_detected!("zcd")); + println!("zcb: {}", is_riscv_feature_detected!("zcb")); + println!("zcmop: {}", is_riscv_feature_detected!("zcmop")); + println!("b: {}", is_riscv_feature_detected!("b")); + println!("zba: {}", is_riscv_feature_detected!("zba")); + println!("zbb: {}", is_riscv_feature_detected!("zbb")); + println!("zbc: {}", is_riscv_feature_detected!("zbc")); + println!("zbs: {}", is_riscv_feature_detected!("zbs")); + println!("zbkb: {}", is_riscv_feature_detected!("zbkb")); + println!("zbkc: {}", is_riscv_feature_detected!("zbkc")); + println!("zbkx: {}", is_riscv_feature_detected!("zbkx")); + println!("zknd: {}", is_riscv_feature_detected!("zknd")); + println!("zkne: {}", is_riscv_feature_detected!("zkne")); + println!("zknh: {}", is_riscv_feature_detected!("zknh")); + println!("zksed: {}", is_riscv_feature_detected!("zksed")); + println!("zksh: {}", is_riscv_feature_detected!("zksh")); + println!("zkr: {}", is_riscv_feature_detected!("zkr")); + println!("zkn: {}", is_riscv_feature_detected!("zkn")); + println!("zks: {}", is_riscv_feature_detected!("zks")); + println!("zk: {}", is_riscv_feature_detected!("zk")); + println!("zkt: {}", is_riscv_feature_detected!("zkt")); + println!("v: {}", is_riscv_feature_detected!("v")); + println!("zve32x: {}", is_riscv_feature_detected!("zve32x")); + println!("zve32f: {}", is_riscv_feature_detected!("zve32f")); + println!("zve64x: {}", is_riscv_feature_detected!("zve64x")); + println!("zve64f: {}", is_riscv_feature_detected!("zve64f")); + println!("zve64d: {}", is_riscv_feature_detected!("zve64d")); + println!("zvfh: {}", is_riscv_feature_detected!("zvfh")); + println!("zvfhmin: {}", is_riscv_feature_detected!("zvfhmin")); + println!("zvfbfmin: {}", is_riscv_feature_detected!("zvfbfmin")); + println!("zvfbfwma: {}", is_riscv_feature_detected!("zvfbfwma")); + println!("zvbb: {}", is_riscv_feature_detected!("zvbb")); + println!("zvbc: {}", is_riscv_feature_detected!("zvbc")); + println!("zvkb: {}", is_riscv_feature_detected!("zvkb")); + println!("zvkg: {}", is_riscv_feature_detected!("zvkg")); + println!("zvkned: {}", is_riscv_feature_detected!("zvkned")); + println!("zvknha: {}", is_riscv_feature_detected!("zvknha")); + println!("zvknhb: {}", is_riscv_feature_detected!("zvknhb")); + println!("zvksed: {}", is_riscv_feature_detected!("zvksed")); + println!("zvksh: {}", is_riscv_feature_detected!("zvksh")); + println!("zvkn: {}", is_riscv_feature_detected!("zvkn")); + println!("zvknc: {}", is_riscv_feature_detected!("zvknc")); + println!("zvkng: {}", is_riscv_feature_detected!("zvkng")); + println!("zvks: {}", is_riscv_feature_detected!("zvks")); + println!("zvksc: {}", is_riscv_feature_detected!("zvksc")); + println!("zvksg: {}", is_riscv_feature_detected!("zvksg")); + println!("zvkt: {}", is_riscv_feature_detected!("zvkt")); + println!("j: {}", is_riscv_feature_detected!("j")); + println!("p: {}", is_riscv_feature_detected!("p")); +} + +#[test] +#[cfg(all(target_arch = "powerpc", target_os = "linux"))] +fn powerpc_linux() { + println!("altivec: {}", is_powerpc_feature_detected!("altivec")); + println!("vsx: {}", is_powerpc_feature_detected!("vsx")); + println!("power8: {}", is_powerpc_feature_detected!("power8")); +} + +#[test] +#[cfg(all( + target_arch = "powerpc64", + any(target_os = "linux", target_os = "freebsd"), +))] +fn powerpc64_linux_or_freebsd() { + println!("altivec: {}", is_powerpc64_feature_detected!("altivec")); + println!("vsx: {}", is_powerpc64_feature_detected!("vsx")); + println!("power8: {}", is_powerpc64_feature_detected!("power8")); + println!("power9: {}", is_powerpc64_feature_detected!("power9")); +} + +#[test] +#[cfg(all(target_arch = "s390x", target_os = "linux",))] +fn s390x_linux() { + println!("vector: {}", is_s390x_feature_detected!("vector")); +} diff --git a/library/std_detect/tests/macro_trailing_commas.rs b/library/std_detect/tests/macro_trailing_commas.rs new file mode 100644 index 00000000000..2fee0abdd57 --- /dev/null +++ b/library/std_detect/tests/macro_trailing_commas.rs @@ -0,0 +1,109 @@ +#![allow(internal_features)] +#![cfg_attr( + any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "arm64ec", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "loongarch32", + target_arch = "loongarch64" + ), + feature(stdarch_internal) +)] +#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))] +#![cfg_attr( + any(target_arch = "aarch64", target_arch = "arm64ec"), + feature(stdarch_aarch64_feature_detection) +)] +#![cfg_attr( + any(target_arch = "powerpc", target_arch = "powerpc64"), + feature(stdarch_powerpc_feature_detection) +)] +#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))] +#![cfg_attr( + any(target_arch = "riscv32", target_arch = "riscv64"), + feature(stdarch_riscv_feature_detection) +)] +#![cfg_attr( + any(target_arch = "loongarch32", target_arch = "loongarch64"), + feature(stdarch_loongarch_feature_detection) +)] + +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "arm64ec", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "loongarch32", + target_arch = "loongarch64" +))] +#[macro_use] +extern crate std_detect; + +#[test] +#[cfg(target_arch = "arm")] +fn arm() { + let _ = is_arm_feature_detected!("neon"); + let _ = is_arm_feature_detected!("neon",); +} + +#[test] +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] +fn aarch64() { + let _ = is_aarch64_feature_detected!("fp"); + let _ = is_aarch64_feature_detected!("fp",); +} + +#[test] +#[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] +fn loongarch() { + let _ = is_loongarch_feature_detected!("lsx"); + let _ = is_loongarch_feature_detected!("lsx",); +} + +#[test] +#[cfg(target_arch = "powerpc")] +fn powerpc() { + let _ = is_powerpc_feature_detected!("altivec"); + let _ = is_powerpc_feature_detected!("altivec",); +} + +#[test] +#[cfg(target_arch = "powerpc64")] +fn powerpc64() { + let _ = is_powerpc64_feature_detected!("altivec"); + let _ = is_powerpc64_feature_detected!("altivec",); +} + +#[test] +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +fn riscv() { + let _ = is_riscv_feature_detected!("zk"); + let _ = is_riscv_feature_detected!("zk",); +} + +#[test] +#[cfg(target_arch = "s390x")] +fn s390x() { + let _ = is_s390x_feature_detected!("vector"); + let _ = is_s390x_feature_detected!("vector",); +} + +#[test] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn x86() { + let _ = is_x86_feature_detected!("sse"); + let _ = is_x86_feature_detected!("sse",); +} diff --git a/library/std_detect/tests/x86-specific.rs b/library/std_detect/tests/x86-specific.rs new file mode 100644 index 00000000000..d9ec79821ba --- /dev/null +++ b/library/std_detect/tests/x86-specific.rs @@ -0,0 +1,117 @@ +#![cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#![allow(internal_features)] +#![feature( + stdarch_internal, + x86_amx_intrinsics, + xop_target_feature, + movrs_target_feature +)] + +#[macro_use] +extern crate std_detect; + +#[test] +fn dump() { + println!("aes: {:?}", is_x86_feature_detected!("aes")); + println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); + println!("rdrand: {:?}", is_x86_feature_detected!("rdrand")); + println!("rdseed: {:?}", is_x86_feature_detected!("rdseed")); + println!("tsc: {:?}", is_x86_feature_detected!("tsc")); + println!("sse: {:?}", is_x86_feature_detected!("sse")); + println!("sse2: {:?}", is_x86_feature_detected!("sse2")); + println!("sse3: {:?}", is_x86_feature_detected!("sse3")); + println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); + println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1")); + println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2")); + println!("sse4a: {:?}", is_x86_feature_detected!("sse4a")); + println!("sha: {:?}", is_x86_feature_detected!("sha")); + println!("f16c: {:?}", is_x86_feature_detected!("f16c")); + println!("avx: {:?}", is_x86_feature_detected!("avx")); + println!("avx2: {:?}", is_x86_feature_detected!("avx2")); + println!("sha512: {:?}", is_x86_feature_detected!("sha512")); + println!("sm3: {:?}", is_x86_feature_detected!("sm3")); + println!("sm4: {:?}", is_x86_feature_detected!("sm4")); + println!("avx512f: {:?}", is_x86_feature_detected!("avx512f")); + println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd")); + println!("avx512er: {:?}", is_x86_feature_detected!("avx512er")); + println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf")); + println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw")); + println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq")); + println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl")); + println!("avx512_ifma: {:?}", is_x86_feature_detected!("avx512ifma")); + println!("avx512vbmi {:?}", is_x86_feature_detected!("avx512vbmi")); + println!( + "avx512_vpopcntdq: {:?}", + is_x86_feature_detected!("avx512vpopcntdq") + ); + println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2")); + println!("gfni: {:?}", is_x86_feature_detected!("gfni")); + println!("vaes: {:?}", is_x86_feature_detected!("vaes")); + println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq")); + println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni")); + println!( + "avx512bitalg: {:?}", + is_x86_feature_detected!("avx512bitalg") + ); + println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16")); + println!( + "avx512vp2intersect: {:?}", + is_x86_feature_detected!("avx512vp2intersect") + ); + println!("avx512fp16: {:?}", is_x86_feature_detected!("avx512fp16")); + println!("fma: {:?}", is_x86_feature_detected!("fma")); + println!("abm: {:?}", is_x86_feature_detected!("abm")); + println!("bmi: {:?}", is_x86_feature_detected!("bmi1")); + println!("bmi2: {:?}", is_x86_feature_detected!("bmi2")); + println!("tbm: {:?}", is_x86_feature_detected!("tbm")); + println!("popcnt: {:?}", is_x86_feature_detected!("popcnt")); + println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); + println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); + println!("xsave: {:?}", is_x86_feature_detected!("xsave")); + println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt")); + println!("xsaves: {:?}", is_x86_feature_detected!("xsaves")); + println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); + println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b")); + println!("adx: {:?}", is_x86_feature_detected!("adx")); + println!("rtm: {:?}", is_x86_feature_detected!("rtm")); + println!("movbe: {:?}", is_x86_feature_detected!("movbe")); + println!("avxvnni: {:?}", is_x86_feature_detected!("avxvnni")); + println!("avxvnniint8: {:?}", is_x86_feature_detected!("avxvnniint8")); + println!( + "avxneconvert: {:?}", + is_x86_feature_detected!("avxneconvert") + ); + println!("avxifma: {:?}", is_x86_feature_detected!("avxifma")); + println!( + "avxvnniint16: {:?}", + is_x86_feature_detected!("avxvnniint16") + ); + println!("amx-bf16: {:?}", is_x86_feature_detected!("amx-bf16")); + println!("amx-tile: {:?}", is_x86_feature_detected!("amx-tile")); + println!("amx-int8: {:?}", is_x86_feature_detected!("amx-int8")); + println!("amx-fp16: {:?}", is_x86_feature_detected!("amx-fp16")); + println!("amx-complex: {:?}", is_x86_feature_detected!("amx-complex")); + println!("xop: {:?}", is_x86_feature_detected!("xop")); + println!("kl: {:?}", is_x86_feature_detected!("kl")); + println!("widekl: {:?}", is_x86_feature_detected!("widekl")); + println!("movrs: {:?}", is_x86_feature_detected!("movrs")); + println!("amx-fp8: {:?}", is_x86_feature_detected!("amx-fp8")); + println!( + "amx-transpose: {:?}", + is_x86_feature_detected!("amx-transpose") + ); + println!("amx-tf32: {:?}", is_x86_feature_detected!("amx-tf32")); + println!("amx-avx512: {:?}", is_x86_feature_detected!("amx-avx512")); + println!("amx-movrs: {:?}", is_x86_feature_detected!("amx-movrs")); +} + +#[test] +#[allow(deprecated)] +fn x86_deprecated() { + println!("avx512gfni {:?}", is_x86_feature_detected!("avx512gfni")); + println!("avx512vaes {:?}", is_x86_feature_detected!("avx512vaes")); + println!( + "avx512vpclmulqdq {:?}", + is_x86_feature_detected!("avx512vpclmulqdq") + ); +} diff --git a/library/stdarch/crates/std_detect/Cargo.toml b/library/stdarch/crates/std_detect/Cargo.toml deleted file mode 100644 index f990e724125..00000000000 --- a/library/stdarch/crates/std_detect/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "std_detect" -version = "0.1.5" -authors = [ - "Alex Crichton ", - "Andrew Gallant ", - "Gonzalo Brito Gadeschi ", -] -description = "`std::detect` - Rust's standard library run-time CPU feature detection." -homepage = "https://github.com/rust-lang/stdarch" -repository = "https://github.com/rust-lang/stdarch" -readme = "README.md" -keywords = ["std", "run-time", "feature", "detection"] -categories = ["hardware-support"] -license = "MIT OR Apache-2.0" -edition = "2024" - -[badges] -is-it-maintained-issue-resolution = { repository = "rust-lang/stdarch" } -is-it-maintained-open-issues = { repository = "rust-lang/stdarch" } -maintenance = { status = "experimental" } - -[dependencies] -cfg-if = "1.0.0" - -# When built as part of libstd -core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } -alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } - -[target.'cfg(not(windows))'.dependencies] -libc = { version = "0.2.0", optional = true, default-features = false } - -[features] -default = [ "std_detect_dlsym_getauxval", "std_detect_file_io" ] -std_detect_file_io = [ "libc" ] -std_detect_dlsym_getauxval = [ "libc" ] -std_detect_env_override = [ "libc" ] -rustc-dep-of-std = [ - "core", - "alloc", -] diff --git a/library/stdarch/crates/std_detect/LICENSE-APACHE b/library/stdarch/crates/std_detect/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e8..00000000000 --- a/library/stdarch/crates/std_detect/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/library/stdarch/crates/std_detect/LICENSE-MIT b/library/stdarch/crates/std_detect/LICENSE-MIT deleted file mode 100644 index 52d82415d8b..00000000000 --- a/library/stdarch/crates/std_detect/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2017 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/library/stdarch/crates/std_detect/README.md b/library/stdarch/crates/std_detect/README.md deleted file mode 100644 index edc90d319a1..00000000000 --- a/library/stdarch/crates/std_detect/README.md +++ /dev/null @@ -1,93 +0,0 @@ -`std::detect` - Rust's standard library run-time CPU feature detection -======= - -The private `std::detect` module implements run-time feature detection in Rust's -standard library. This allows detecting whether the CPU the binary runs on -supports certain features, like SIMD instructions. - -# Usage - -`std::detect` APIs are available as part of `libstd`. Prefer using it via the -standard library than through this crate. Unstable features of `std::detect` are -available on nightly Rust behind various feature-gates. - -If you need run-time feature detection in `#[no_std]` environments, Rust `core` -library cannot help you. By design, Rust `core` is platform independent, but -performing run-time feature detection requires a certain level of cooperation -from the platform. - -You can then manually include `std_detect` as a dependency to get similar -run-time feature detection support than the one offered by Rust's standard -library. We intend to make `std_detect` more flexible and configurable in this -regard to better serve the needs of `#[no_std]` targets. - -# Features - -* `std_detect_dlsym_getauxval` (enabled by default, requires `libc`): Enable to -use `libc::dlsym` to query whether [`getauxval`] is linked into the binary. When -this is not the case, this feature allows other fallback methods to perform -run-time feature detection. When this feature is disabled, `std_detect` assumes -that [`getauxval`] is linked to the binary. If that is not the case the behavior -is undefined. - - Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets - because we can safely assume `getauxval` is linked to the binary. - * `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) - have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). - * `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) - use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) - * `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) - * `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) - have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). - -* `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature -detection using file APIs (e.g. `/proc/self/auxv`, etc.) if other more performant -methods fail. This feature requires `libstd` as a dependency, preventing the -crate from working on applications in which `std` is not available. - -[`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html - -# Platform support - -* All `x86`/`x86_64` targets are supported on all platforms by querying the - `cpuid` instruction directly for the features supported by the hardware and - the operating system. `std_detect` assumes that the binary is an user-space - application. - -* Linux/Android: - * `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `loongarch{32,64}`, `s390x`: - `std_detect` supports these on Linux by querying ELF auxiliary vectors (using `getauxval` - when available), and if that fails, by querying `/proc/self/auxv`. - * `arm64`: partial support for doing run-time feature detection by directly - querying `mrs` is implemented for Linux >= 4.11, but not enabled by default. - * `riscv{32,64}`: - `std_detect` supports these on Linux by querying `riscv_hwprobe`, and - by querying ELF auxiliary vectors (using `getauxval` when available). - -* FreeBSD: - * `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF - auxiliary vectors using `sysctl`. - * `arm64`: run-time feature detection is implemented by directly querying `mrs`. - -* OpenBSD: - * `arm64`: run-time feature detection is implemented by querying `sysctl`. - -* Windows: - * `arm64`: run-time feature detection is implemented by querying `IsProcessorFeaturePresent`. - -# License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -# Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in `std_detect` by you, as defined in the Apache-2.0 license, -shall be dual licensed as above, without any additional terms or conditions. diff --git a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs deleted file mode 100644 index 13570a25c1c..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs +++ /dev/null @@ -1,259 +0,0 @@ -//! Aarch64 run-time features. - -features! { - @TARGET: aarch64; - @CFG: any(target_arch = "aarch64", target_arch = "arm64ec"); - @MACRO_NAME: is_aarch64_feature_detected; - @MACRO_ATTRS: - /// This macro tests, at runtime, whether an `aarch64` feature is enabled on aarch64 platforms. - /// Currently most features are only supported on linux-based platforms. - /// - /// This macro takes one argument which is a string literal of the feature being tested for. - /// The feature names are mostly taken from their FEAT_* definitions in the [ARM Architecture - /// Reference Manual][docs]. - /// - /// ## Supported arguments - /// - /// * `"aes"` - FEAT_AES & FEAT_PMULL - /// * `"asimd"` or "neon" - FEAT_AdvSIMD - /// * `"bf16"` - FEAT_BF16 - /// * `"bti"` - FEAT_BTI - /// * `"crc"` - FEAT_CRC - /// * `"cssc"` - FEAT_CSSC - /// * `"dit"` - FEAT_DIT - /// * `"dotprod"` - FEAT_DotProd - /// * `"dpb"` - FEAT_DPB - /// * `"dpb2"` - FEAT_DPB2 - /// * `"ecv"` - FEAT_ECV - /// * `"f32mm"` - FEAT_F32MM - /// * `"f64mm"` - FEAT_F64MM - /// * `"faminmax"` - FEAT_FAMINMAX - /// * `"fcma"` - FEAT_FCMA - /// * `"fhm"` - FEAT_FHM - /// * `"flagm"` - FEAT_FLAGM - /// * `"flagm2"` - FEAT_FLAGM2 - /// * `"fp"` - FEAT_FP - /// * `"fp16"` - FEAT_FP16 - /// * `"fp8"` - FEAT_FP8 - /// * `"fp8dot2"` - FEAT_FP8DOT2 - /// * `"fp8dot4"` - FEAT_FP8DOT4 - /// * `"fp8fma"` - FEAT_FP8FMA - /// * `"fpmr"` - FEAT_FPMR - /// * `"frintts"` - FEAT_FRINTTS - /// * `"hbc"` - FEAT_HBC - /// * `"i8mm"` - FEAT_I8MM - /// * `"jsconv"` - FEAT_JSCVT - /// * `"lse"` - FEAT_LSE - /// * `"lse128"` - FEAT_LSE128 - /// * `"lse2"` - FEAT_LSE2 - /// * `"lut"` - FEAT_LUT - /// * `"mops"` - FEAT_MOPS - /// * `"mte"` - FEAT_MTE & FEAT_MTE2 - /// * `"paca"` - FEAT_PAuth (address authentication) - /// * `"pacg"` - FEAT_Pauth (generic authentication) - /// * `"pauth-lr"` - FEAT_PAuth_LR - /// * `"pmull"` - FEAT_PMULL - /// * `"rand"` - FEAT_RNG - /// * `"rcpc"` - FEAT_LRCPC - /// * `"rcpc2"` - FEAT_LRCPC2 - /// * `"rcpc3"` - FEAT_LRCPC3 - /// * `"rdm"` - FEAT_RDM - /// * `"sb"` - FEAT_SB - /// * `"sha2"` - FEAT_SHA1 & FEAT_SHA256 - /// * `"sha3"` - FEAT_SHA512 & FEAT_SHA3 - /// * `"sm4"` - FEAT_SM3 & FEAT_SM4 - /// * `"sme"` - FEAT_SME - /// * `"sme-b16b16"` - FEAT_SME_B16B16 - /// * `"sme-f16f16"` - FEAT_SME_F16F16 - /// * `"sme-f64f64"` - FEAT_SME_F64F64 - /// * `"sme-f8f16"` - FEAT_SME_F8F16 - /// * `"sme-f8f32"` - FEAT_SME_F8F32 - /// * `"sme-fa64"` - FEAT_SME_FA64 - /// * `"sme-i16i64"` - FEAT_SME_I16I64 - /// * `"sme-lutv2"` - FEAT_SME_LUTv2 - /// * `"sme2"` - FEAT_SME2 - /// * `"sme2p1"` - FEAT_SME2p1 - /// * `"ssbs"` - FEAT_SSBS & FEAT_SSBS2 - /// * `"ssve-fp8dot2"` - FEAT_SSVE_FP8DOT2 - /// * `"ssve-fp8dot4"` - FEAT_SSVE_FP8DOT4 - /// * `"ssve-fp8fma"` - FEAT_SSVE_FP8FMA - /// * `"sve"` - FEAT_SVE - /// * `"sve-b16b16"` - FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) - /// * `"sve2"` - FEAT_SVE2 - /// * `"sve2-aes"` - FEAT_SVE_AES & FEAT_SVE_PMULL128 (SVE2 AES crypto) - /// * `"sve2-bitperm"` - FEAT_SVE2_BitPerm - /// * `"sve2-sha3"` - FEAT_SVE2_SHA3 - /// * `"sve2-sm4"` - FEAT_SVE2_SM4 - /// * `"sve2p1"` - FEAT_SVE2p1 - /// * `"tme"` - FEAT_TME - /// * `"wfxt"` - FEAT_WFxT - /// - /// [docs]: https://developer.arm.com/documentation/ddi0487/latest - #[stable(feature = "simd_aarch64", since = "1.60.0")] - @BIND_FEATURE_NAME: "asimd"; "neon"; - @NO_RUNTIME_DETECTION: "ras"; - @NO_RUNTIME_DETECTION: "v8.1a"; - @NO_RUNTIME_DETECTION: "v8.2a"; - @NO_RUNTIME_DETECTION: "v8.3a"; - @NO_RUNTIME_DETECTION: "v8.4a"; - @NO_RUNTIME_DETECTION: "v8.5a"; - @NO_RUNTIME_DETECTION: "v8.6a"; - @NO_RUNTIME_DETECTION: "v8.7a"; - @NO_RUNTIME_DETECTION: "v8.8a"; - @NO_RUNTIME_DETECTION: "v8.9a"; - @NO_RUNTIME_DETECTION: "v9.1a"; - @NO_RUNTIME_DETECTION: "v9.2a"; - @NO_RUNTIME_DETECTION: "v9.3a"; - @NO_RUNTIME_DETECTION: "v9.4a"; - @NO_RUNTIME_DETECTION: "v9.5a"; - @NO_RUNTIME_DETECTION: "v9a"; - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] asimd: "neon"; - /// FEAT_AdvSIMD (Advanced SIMD/NEON) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pmull: "pmull"; - implied by target_features: ["aes"]; - /// FEAT_PMULL (Polynomial Multiply) - Implied by `aes` target_feature - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp: "fp"; - implied by target_features: ["neon"]; - /// FEAT_FP (Floating point support) - Implied by `neon` target_feature - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] aes: "aes"; - /// FEAT_AES (AES SIMD instructions) & FEAT_PMULL (PMULL{2}, 64-bit operand variants) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] bf16: "bf16"; - /// FEAT_BF16 (BFloat16 type, plus MM instructions, plus ASIMD support) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] bti: "bti"; - /// FEAT_BTI (Branch Target Identification) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] crc: "crc"; - /// FEAT_CRC32 (Cyclic Redundancy Check) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] cssc: "cssc"; - /// FEAT_CSSC (Common Short Sequence Compression instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dit: "dit"; - /// FEAT_DIT (Data Independent Timing instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dpb: "dpb"; - /// FEAT_DPB (aka dcpop - data cache clean to point of persistence) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dpb2: "dpb2"; - /// FEAT_DPB2 (aka dcpodp - data cache clean to point of deep persistence) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dotprod: "dotprod"; - /// FEAT_DotProd (Vector Dot-Product - ASIMDDP) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ecv: "ecv"; - /// FEAT_ECV (Enhanced Counter Virtualization) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] f32mm: "f32mm"; - /// FEAT_F32MM (single-precision matrix multiplication) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] f64mm: "f64mm"; - /// FEAT_F64MM (double-precision matrix multiplication) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] faminmax: "faminmax"; - /// FEAT_FAMINMAX (FAMIN and FAMAX SIMD/SVE/SME instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fcma: "fcma"; - /// FEAT_FCMA (float complex number operations) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fhm: "fhm"; - /// FEAT_FHM (fp16 multiplication instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] flagm: "flagm"; - /// FEAT_FLAGM (flag manipulation instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] flagm2: "flagm2"; - /// FEAT_FLAGM2 (flag manipulation instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp16: "fp16"; - /// FEAT_FP16 (Half-float support) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8: "fp8"; - /// FEAT_FP8 (F8CVT Instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8dot2: "fp8dot2"; - /// FEAT_FP8DOT2 (F8DP2 Instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8dot4: "fp8dot4"; - /// FEAT_FP8DOT4 (F8DP4 Instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fp8fma: "fp8fma"; - /// FEAT_FP8FMA (F8FMA Instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] fpmr: "fpmr"; - without cfg check: true; - /// FEAT_FPMR (Special-purpose AArch64-FPMR register) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] frintts: "frintts"; - /// FEAT_FRINTTS (float to integer rounding instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] hbc: "hbc"; - /// FEAT_HBC (Hinted conditional branches) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] i8mm: "i8mm"; - /// FEAT_I8MM (integer matrix multiplication, plus ASIMD support) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] jsconv: "jsconv"; - /// FEAT_JSCVT (JavaScript float conversion instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] lse: "lse"; - /// FEAT_LSE (Large System Extension - atomics) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] lse128: "lse128"; - /// FEAT_LSE128 (128-bit atomics) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] lse2: "lse2"; - /// FEAT_LSE2 (unaligned and register-pair atomics) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] lut: "lut"; - /// FEAT_LUT (Lookup Table Instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] mops: "mops"; - /// FEAT_MOPS (Standardization of memory operations) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] mte: "mte"; - /// FEAT_MTE & FEAT_MTE2 (Memory Tagging Extension) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] paca: "paca"; - /// FEAT_PAuth (address authentication) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pacg: "pacg"; - /// FEAT_PAuth (generic authentication) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] pauth_lr: "pauth-lr"; - /// FEAT_PAuth_LR - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rand: "rand"; - /// FEAT_RNG (Random Number Generator) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rcpc: "rcpc"; - /// FEAT_LRCPC (Release consistent Processor consistent) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rcpc2: "rcpc2"; - /// FEAT_LRCPC2 (RCPC with immediate offsets) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] rcpc3: "rcpc3"; - /// FEAT_LRCPC3 (RCPC Instructions v3) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rdm: "rdm"; - /// FEAT_RDM (Rounding Doubling Multiply - ASIMDRDM) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sb: "sb"; - /// FEAT_SB (speculation barrier) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sha2: "sha2"; - /// FEAT_SHA1 & FEAT_SHA256 (SHA1 & SHA2-256 instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sha3: "sha3"; - /// FEAT_SHA512 & FEAT_SHA3 (SHA2-512 & SHA3 instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sm4: "sm4"; - /// FEAT_SM3 & FEAT_SM4 (SM3 & SM4 instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme: "sme"; - /// FEAT_SME (Scalable Matrix Extension) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme2: "sme2"; - /// FEAT_SME2 (SME Version 2) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme2p1: "sme2p1"; - /// FEAT_SME2p1 (SME Version 2.1) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_b16b16: "sme-b16b16"; - /// FEAT_SME_B16B16 - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f16f16: "sme-f16f16"; - /// FEAT_SME_F16F16 (Non-widening half-precision FP16 to FP16 arithmetic for SME2) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f64f64: "sme-f64f64"; - /// FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f8f16: "sme-f8f16"; - /// FEAT_SME_F8F16 - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_f8f32: "sme-f8f32"; - /// FEAT_SME_F8F32 - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_fa64: "sme-fa64"; - /// FEAT_SME_FA64 (Full A64 instruction set support in Streaming SVE mode) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_i16i64: "sme-i16i64"; - /// FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sme_lutv2: "sme-lutv2"; - /// FEAT_SME_LUTv2 (LUTI4 Instruction) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] ssbs: "ssbs"; - /// FEAT_SSBS & FEAT_SSBS2 (speculative store bypass safe) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ssve_fp8dot2: "ssve-fp8dot2"; - /// FEAT_SSVE_FP8DOT2 - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ssve_fp8dot4: "ssve-fp8dot4"; - /// FEAT_SSVE_FP8DOT4 - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] ssve_fp8fma: "ssve-fp8fma"; - /// FEAT_SSVE_FP8FMA - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve: "sve"; - /// FEAT_SVE (Scalable Vector Extension) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2: "sve2"; - /// FEAT_SVE2 (Scalable Vector Extension 2) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sve2p1: "sve2p1"; - /// FEAT_SVE2p1 (Scalable Vector Extension 2.1) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_aes: "sve2-aes"; - /// FEAT_SVE_AES & FEAT_SVE_PMULL128 (SVE2 AES crypto) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] sve_b16b16: "sve-b16b16"; - /// FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_bitperm: "sve2-bitperm"; - /// FEAT_SVE_BitPerm (SVE2 bit permutation instructions) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_sha3: "sve2-sha3"; - /// FEAT_SVE_SHA3 (SVE2 SHA3 crypto) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_sm4: "sve2-sm4"; - /// FEAT_SVE_SM4 (SVE2 SM4 crypto) - @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] tme: "tme"; - /// FEAT_TME (Transactional Memory Extensions) - @FEATURE: #[unstable(feature = "stdarch_aarch64_feature_detection", issue = "127764")] wfxt: "wfxt"; - /// FEAT_WFxT (WFET and WFIT Instructions) -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/arm.rs b/library/stdarch/crates/std_detect/src/detect/arch/arm.rs deleted file mode 100644 index c3c8883ce31..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/arm.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Run-time feature detection on ARM Aarch32. - -features! { - @TARGET: arm; - @CFG: target_arch = "arm"; - @MACRO_NAME: is_arm_feature_detected; - @MACRO_ATTRS: - /// Checks if `arm` feature is enabled. - #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] - @NO_RUNTIME_DETECTION: "v7"; - @NO_RUNTIME_DETECTION: "vfp2"; - @NO_RUNTIME_DETECTION: "vfp3"; - @NO_RUNTIME_DETECTION: "vfp4"; - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] neon: "neon"; - /// ARM Advanced SIMD (NEON) - Aarch32 - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] pmull: "pmull"; - without cfg check: true; - /// Polynomial Multiply - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] crc: "crc"; - /// CRC32 (Cyclic Redundancy Check) - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] aes: "aes"; - /// FEAT_AES (AES instructions) - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] sha2: "sha2"; - /// FEAT_SHA1 & FEAT_SHA256 (SHA1 & SHA2-256 instructions) - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] i8mm: "i8mm"; - /// FEAT_I8MM (integer matrix multiplication, plus ASIMD support) - @FEATURE: #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] dotprod: "dotprod"; - /// FEAT_DotProd (Vector Dot-Product - ASIMDDP) -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/loongarch.rs b/library/stdarch/crates/std_detect/src/detect/arch/loongarch.rs deleted file mode 100644 index 68fc600fa8e..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/loongarch.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Run-time feature detection on LoongArch. - -features! { - @TARGET: loongarch; - @CFG: any(target_arch = "loongarch32", target_arch = "loongarch64"); - @MACRO_NAME: is_loongarch_feature_detected; - @MACRO_ATTRS: - /// Checks if `loongarch` feature is enabled. - /// Supported arguments are: - /// - /// * `"f"` - /// * `"d"` - /// * `"frecipe"` - /// * `"div32"` - /// * `"lsx"` - /// * `"lasx"` - /// * `"lam-bh"` - /// * `"lamcas"` - /// * `"ld-seq-sa"` - /// * `"scq"` - /// * `"lbt"` - /// * `"lvz"` - /// * `"ual"` - #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] f: "f"; - /// F - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] d: "d"; - /// D - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] frecipe: "frecipe"; - /// Frecipe - @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] div32: "div32"; - /// Div32 - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lsx: "lsx"; - /// LSX - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lasx: "lasx"; - /// LASX - @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] lam_bh: "lam-bh"; - /// LAM-BH - @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] lamcas: "lamcas"; - /// LAM-CAS - @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] ld_seq_sa: "ld-seq-sa"; - /// LD-SEQ-SA - @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] scq: "scq"; - /// SCQ - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lbt: "lbt"; - /// LBT - @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] lvz: "lvz"; - /// LVZ - @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] ual: "ual"; - /// UAL -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mips.rs b/library/stdarch/crates/std_detect/src/detect/arch/mips.rs deleted file mode 100644 index e185fdfcaac..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/mips.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! Run-time feature detection on MIPS. - -features! { - @TARGET: mips; - @CFG: target_arch = "mips"; - @MACRO_NAME: is_mips_feature_detected; - @MACRO_ATTRS: - /// Checks if `mips` feature is enabled. - #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] - @FEATURE: #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] msa: "msa"; - /// MIPS SIMD Architecture (MSA) -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs b/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs deleted file mode 100644 index 69fe4869d30..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! Run-time feature detection on MIPS64. - -features! { - @TARGET: mips64; - @CFG: target_arch = "mips64"; - @MACRO_NAME: is_mips64_feature_detected; - @MACRO_ATTRS: - /// Checks if `mips64` feature is enabled. - #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] - @FEATURE: #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] msa: "msa"; - /// MIPS SIMD Architecture (MSA) -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mod.rs b/library/stdarch/crates/std_detect/src/detect/arch/mod.rs deleted file mode 100644 index b0be554ed89..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/mod.rs +++ /dev/null @@ -1,75 +0,0 @@ -#![allow(dead_code)] - -use cfg_if::cfg_if; - -// Export the macros for all supported architectures. -#[macro_use] -mod x86; -#[macro_use] -mod arm; -#[macro_use] -mod aarch64; -#[macro_use] -mod riscv; -#[macro_use] -mod powerpc; -#[macro_use] -mod powerpc64; -#[macro_use] -mod mips; -#[macro_use] -mod mips64; -#[macro_use] -mod loongarch; -#[macro_use] -mod s390x; - -cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - #[stable(feature = "simd_x86", since = "1.27.0")] - pub use x86::*; - } else if #[cfg(target_arch = "arm")] { - #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] - pub use arm::*; - } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { - #[stable(feature = "simd_aarch64", since = "1.60.0")] - pub use aarch64::*; - } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { - #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] - pub use riscv::*; - } else if #[cfg(target_arch = "powerpc")] { - #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] - pub use powerpc::*; - } else if #[cfg(target_arch = "powerpc64")] { - #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] - pub use powerpc64::*; - } else if #[cfg(target_arch = "mips")] { - #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] - pub use mips::*; - } else if #[cfg(target_arch = "mips64")] { - #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] - pub use mips64::*; - } else if #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] { - #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] - pub use loongarch::*; - } else if #[cfg(target_arch = "s390x")] { - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - pub use s390x::*; - } else { - // Unimplemented architecture: - #[doc(hidden)] - pub(crate) enum Feature { - Null - } - #[doc(hidden)] - #[unstable(feature = "stdarch_internal", issue = "none")] - pub mod __is_feature_detected {} - - impl Feature { - #[doc(hidden)] - pub(crate) fn from_str(_s: &str) -> Result { Err(()) } - #[doc(hidden)] - pub(crate) fn to_str(self) -> &'static str { "" } - } - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs b/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs deleted file mode 100644 index c390993a48a..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Run-time feature detection on PowerPC. - -features! { - @TARGET: powerpc; - @CFG: target_arch = "powerpc"; - @MACRO_NAME: is_powerpc_feature_detected; - @MACRO_ATTRS: - /// Checks if `powerpc` feature is enabled. - #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] altivec: "altivec"; - /// Altivec - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] vsx: "vsx"; - /// VSX - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8: "power8"; - without cfg check: true; - /// Power8 - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_altivec: "power8-altivec"; - /// Power8 altivec - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_vector: "power8-vector"; - /// Power8 vector - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_crypto: "power8-crypto"; - /// Power8 crypto - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9: "power9"; - without cfg check: true; - /// Power9 - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_altivec: "power9-altivec"; - /// Power9 altivec - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_vector: "power9-vector"; - /// Power9 vector -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs b/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs deleted file mode 100644 index cf05baa6f79..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Run-time feature detection on PowerPC64. - -features! { - @TARGET: powerpc64; - @CFG: target_arch = "powerpc64"; - @MACRO_NAME: is_powerpc64_feature_detected; - @MACRO_ATTRS: - /// Checks if `powerpc` feature is enabled. - #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] altivec: "altivec"; - /// Altivec - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] vsx: "vsx"; - /// VSX - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8: "power8"; - without cfg check: true; - /// Power8 - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_altivec: "power8-altivec"; - /// Power8 altivec - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_vector: "power8-vector"; - /// Power8 vector - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power8_crypto: "power8-crypto"; - /// Power8 crypto - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9: "power9"; - without cfg check: true; - /// Power9 - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_altivec: "power9-altivec"; - /// Power9 altivec - @FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] power9_vector: "power9-vector"; - /// Power9 vector -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs b/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs deleted file mode 100644 index b86190d7bbf..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs +++ /dev/null @@ -1,344 +0,0 @@ -//! Run-time feature detection on RISC-V. - -features! { - @TARGET: riscv; - @CFG: any(target_arch = "riscv32", target_arch = "riscv64"); - @MACRO_NAME: is_riscv_feature_detected; - @MACRO_ATTRS: - /// A macro to test at *runtime* whether instruction sets are available on - /// RISC-V platforms. - /// - /// RISC-V standard defined the base sets and the extension sets. - /// The base sets are RV32I, RV64I, RV32E or RV128I. Any RISC-V platform - /// must support one base set and/or multiple extension sets. - /// - /// Any RISC-V standard instruction sets can be in state of either ratified, - /// frozen or draft. The version and status of current standard instruction - /// sets can be checked out from preface section of the [ISA manual]. - /// - /// Platform may define and support their own custom instruction sets with - /// ISA prefix X. These sets are highly platform specific and should be - /// detected with their own platform support crates. - /// - /// [ISA manual]: https://riscv.org/specifications/ratified/ - /// - /// # Platform-specific/agnostic Behavior and Availability - /// - /// Runtime detection depends on the platform-specific feature detection - /// facility and its availability per feature is - /// highly platform/version-specific. - /// - /// Still, a best-effort attempt is performed to enable subset/dependent - /// features if a superset feature is enabled regardless of the platform. - /// For instance, if the A extension (`"a"`) is enabled, its subsets (the - /// Zalrsc and Zaamo extensions; `"zalrsc"` and `"zaamo"`) are also enabled. - /// Likewise, if the F extension (`"f"`) is enabled, one of its dependencies - /// (the Zicsr extension `"zicsr"`) is also enabled. - /// - /// # Unprivileged Specification - /// - /// The supported ratified RISC-V instruction sets are as follows: - /// - /// * RV32E: `"rv32e"` - /// * RV32I: `"rv32i"` - /// * RV64I: `"rv64i"` - /// * A: `"a"` - /// * Zaamo: `"zaamo"` - /// * Zalrsc: `"zalrsc"` - /// * B: `"b"` - /// * Zba: `"zba"` - /// * Zbb: `"zbb"` - /// * Zbs: `"zbs"` - /// * C: `"c"` - /// * Zca: `"zca"` - /// * Zcd: `"zcd"` (if D is enabled) - /// * Zcf: `"zcf"` (if F is enabled on RV32) - /// * D: `"d"` - /// * F: `"f"` - /// * M: `"m"` - /// * Q: `"q"` - /// * V: `"v"` - /// * Zve32x: `"zve32x"` - /// * Zve32f: `"zve32f"` - /// * Zve64x: `"zve64x"` - /// * Zve64f: `"zve64f"` - /// * Zve64d: `"zve64d"` - /// * Zicbom: `"zicbom"` - /// * Zicboz: `"zicboz"` - /// * Zicntr: `"zicntr"` - /// * Zicond: `"zicond"` - /// * Zicsr: `"zicsr"` - /// * Zifencei: `"zifencei"` - /// * Zihintntl: `"zihintntl"` - /// * Zihintpause: `"zihintpause"` - /// * Zihpm: `"zihpm"` - /// * Zimop: `"zimop"` - /// * Zacas: `"zacas"` - /// * Zawrs: `"zawrs"` - /// * Zfa: `"zfa"` - /// * Zfbfmin: `"zfbfmin"` - /// * Zfh: `"zfh"` - /// * Zfhmin: `"zfhmin"` - /// * Zfinx: `"zfinx"` - /// * Zdinx: `"zdinx"` - /// * Zhinx: `"zhinx"` - /// * Zhinxmin: `"zhinxmin"` - /// * Zcb: `"zcb"` - /// * Zcmop: `"zcmop"` - /// * Zbc: `"zbc"` - /// * Zbkb: `"zbkb"` - /// * Zbkc: `"zbkc"` - /// * Zbkx: `"zbkx"` - /// * Zk: `"zk"` - /// * Zkn: `"zkn"` - /// * Zknd: `"zknd"` - /// * Zkne: `"zkne"` - /// * Zknh: `"zknh"` - /// * Zkr: `"zkr"` - /// * Zks: `"zks"` - /// * Zksed: `"zksed"` - /// * Zksh: `"zksh"` - /// * Zkt: `"zkt"` - /// * Zvbb: `"zvbb"` - /// * Zvbc: `"zvbc"` - /// * Zvfbfmin: `"zvfbfmin"` - /// * Zvfbfwma: `"zvfbfwma"` - /// * Zvfh: `"zvfh"` - /// * Zvfhmin: `"zvfhmin"` - /// * Zvkb: `"zvkb"` - /// * Zvkg: `"zvkg"` - /// * Zvkn: `"zvkn"` - /// * Zvkned: `"zvkned"` - /// * Zvknha: `"zvknha"` - /// * Zvknhb: `"zvknhb"` - /// * Zvknc: `"zvknc"` - /// * Zvkng: `"zvkng"` - /// * Zvks: `"zvks"` - /// * Zvksed: `"zvksed"` - /// * Zvksh: `"zvksh"` - /// * Zvksc: `"zvksc"` - /// * Zvksg: `"zvksg"` - /// * Zvkt: `"zvkt"` - /// * Ztso: `"ztso"` - /// - /// There's also bases and extensions marked as standard instruction set, - /// but they are in frozen or draft state. These instruction sets are also - /// reserved by this macro and can be detected in the future platforms. - /// - /// Draft RISC-V instruction sets: - /// - /// * RV128I: `"rv128i"` - /// * J: `"j"` - /// * P: `"p"` - /// * Zam: `"zam"` - /// - /// # Performance Hints - /// - /// The two features below define performance hints for unaligned - /// scalar/vector memory accesses, respectively. If enabled, it denotes that - /// corresponding unaligned memory access is reasonably fast. - /// - /// * `"unaligned-scalar-mem"` - /// * Runtime detection requires Linux kernel version 6.4 or later. - /// * `"unaligned-vector-mem"` - /// * Runtime detection requires Linux kernel version 6.13 or later. - #[stable(feature = "riscv_ratified", since = "1.78.0")] - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv32i: "rv32i"; - without cfg check: true; - /// RV32I Base Integer Instruction Set - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv32e: "rv32e"; - without cfg check: true; - /// RV32E Base Integer Instruction Set - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv64i: "rv64i"; - without cfg check: true; - /// RV64I Base Integer Instruction Set - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] rv128i: "rv128i"; - without cfg check: true; - /// RV128I Base Integer Instruction Set - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_scalar_mem: "unaligned-scalar-mem"; - /// Has reasonably performant unaligned scalar - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_vector_mem: "unaligned-vector-mem"; - /// Has reasonably performant unaligned vector - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicsr: "zicsr"; - /// "Zicsr" Extension for Control and Status Register (CSR) Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicntr: "zicntr"; - /// "Zicntr" Extension for Base Counters and Timers - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihpm: "zihpm"; - /// "Zihpm" Extension for Hardware Performance Counters - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zifencei: "zifencei"; - /// "Zifencei" Extension for Instruction-Fetch Fence - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihintntl: "zihintntl"; - /// "Zihintntl" Extension for Non-Temporal Locality Hints - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihintpause: "zihintpause"; - /// "Zihintpause" Extension for Pause Hint - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zimop: "zimop"; - /// "Zimop" Extension for May-Be-Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicbom: "zicbom"; - /// "Zicbom" Extension for Cache-Block Management Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicboz: "zicboz"; - /// "Zicboz" Extension for Cache-Block Zero Instruction - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicond: "zicond"; - /// "Zicond" Extension for Integer Conditional Operations - - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] m: "m"; - /// "M" Extension for Integer Multiplication and Division - - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] a: "a"; - /// "A" Extension for Atomic Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zalrsc: "zalrsc"; - /// "Zalrsc" Extension for Load-Reserved/Store-Conditional Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zaamo: "zaamo"; - /// "Zaamo" Extension for Atomic Memory Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zawrs: "zawrs"; - /// "Zawrs" Extension for Wait-on-Reservation-Set Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zacas: "zacas"; - /// "Zacas" Extension for Atomic Compare-and-Swap (CAS) Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zam: "zam"; - without cfg check: true; - /// "Zam" Extension for Misaligned Atomics - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] ztso: "ztso"; - /// "Ztso" Extension for Total Store Ordering - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] f: "f"; - /// "F" Extension for Single-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] d: "d"; - /// "D" Extension for Double-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] q: "q"; - without cfg check: true; - /// "Q" Extension for Quad-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfh: "zfh"; - /// "Zfh" Extension for Half-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfhmin: "zfhmin"; - /// "Zfhmin" Extension for Minimal Half-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfa: "zfa"; - /// "Zfa" Extension for Additional Floating-Point Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfbfmin: "zfbfmin"; - /// "Zfbfmin" Extension for Scalar BF16 Converts - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zfinx: "zfinx"; - /// "Zfinx" Extension for Single-Precision Floating-Point in Integer Registers - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zdinx: "zdinx"; - /// "Zdinx" Extension for Double-Precision Floating-Point in Integer Registers - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zhinx: "zhinx"; - /// "Zhinx" Extension for Half-Precision Floating-Point in Integer Registers - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zhinxmin: "zhinxmin"; - /// "Zhinxmin" Extension for Minimal Half-Precision Floating-Point in Integer Registers - - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] c: "c"; - /// "C" Extension for Compressed Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zca: "zca"; - /// "Zca" Compressed Instructions excluding Floating-Point Loads/Stores - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcf: "zcf"; - without cfg check: true; - /// "Zcf" Compressed Instructions for Single-Precision Floating-Point Loads/Stores on RV32 - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcd: "zcd"; - without cfg check: true; - /// "Zcd" Compressed Instructions for Double-Precision Floating-Point Loads/Stores - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcb: "zcb"; - /// "Zcb" Simple Code-size Saving Compressed Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcmop: "zcmop"; - /// "Zcmop" Extension for Compressed May-Be-Operations - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] b: "b"; - /// "B" Extension for Bit Manipulation - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zba: "zba"; - /// "Zba" Extension for Address Generation - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbb: "zbb"; - /// "Zbb" Extension for Basic Bit-Manipulation - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbc: "zbc"; - /// "Zbc" Extension for Carry-less Multiplication - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbs: "zbs"; - /// "Zbs" Extension for Single-Bit Instructions - - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbkb: "zbkb"; - /// "Zbkb" Extension for Bit-Manipulation for Cryptography - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbkc: "zbkc"; - /// "Zbkc" Extension for Carry-less Multiplication for Cryptography - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zbkx: "zbkx"; - /// "Zbkx" Extension for Crossbar Permutations - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zknd: "zknd"; - /// "Zknd" Cryptography Extension for NIST Suite: AES Decryption - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkne: "zkne"; - /// "Zkne" Cryptography Extension for NIST Suite: AES Encryption - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zknh: "zknh"; - /// "Zknh" Cryptography Extension for NIST Suite: Hash Function Instructions - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zksed: "zksed"; - /// "Zksed" Cryptography Extension for ShangMi Suite: SM4 Block Cipher Instructions - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zksh: "zksh"; - /// "Zksh" Cryptography Extension for ShangMi Suite: SM3 Hash Function Instructions - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkr: "zkr"; - /// "Zkr" Entropy Source Extension - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkn: "zkn"; - /// "Zkn" Cryptography Extension for NIST Algorithm Suite - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zks: "zks"; - /// "Zks" Cryptography Extension for ShangMi Algorithm Suite - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zk: "zk"; - /// "Zk" Cryptography Extension for Standard Scalar Cryptography - @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zkt: "zkt"; - /// "Zkt" Cryptography Extension for Data Independent Execution Latency - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] v: "v"; - /// "V" Extension for Vector Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32x: "zve32x"; - /// "Zve32x" Vector Extension for Embedded Processors (32-bit+; Integer) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32f: "zve32f"; - /// "Zve32f" Vector Extension for Embedded Processors (32-bit+; with Single-Precision Floating-Point) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64x: "zve64x"; - /// "Zve64x" Vector Extension for Embedded Processors (64-bit+; Integer) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64f: "zve64f"; - /// "Zve64f" Vector Extension for Embedded Processors (64-bit+; with Single-Precision Floating-Point) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64d: "zve64d"; - /// "Zve64d" Vector Extension for Embedded Processors (64-bit+; with Double-Precision Floating-Point) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfh: "zvfh"; - /// "Zvfh" Vector Extension for Half-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfhmin: "zvfhmin"; - /// "Zvfhmin" Vector Extension for Minimal Half-Precision Floating-Point - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfbfmin: "zvfbfmin"; - /// "Zvfbfmin" Vector Extension for BF16 Converts - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfbfwma: "zvfbfwma"; - /// "Zvfbfwma" Vector Extension for BF16 Widening Multiply-Add - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbb: "zvbb"; - /// "Zvbb" Extension for Vector Basic Bit-Manipulation - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbc: "zvbc"; - /// "Zvbc" Extension for Vector Carryless Multiplication - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkb: "zvkb"; - /// "Zvkb" Extension for Vector Cryptography Bit-Manipulation - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkg: "zvkg"; - /// "Zvkg" Cryptography Extension for Vector GCM/GMAC - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkned: "zvkned"; - /// "Zvkned" Cryptography Extension for NIST Suite: Vector AES Block Cipher - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknha: "zvknha"; - /// "Zvknha" Cryptography Extension for Vector SHA-2 Secure Hash (SHA-256) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknhb: "zvknhb"; - /// "Zvknhb" Cryptography Extension for Vector SHA-2 Secure Hash (SHA-256/512) - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksed: "zvksed"; - /// "Zvksed" Cryptography Extension for ShangMi Suite: Vector SM4 Block Cipher - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksh: "zvksh"; - /// "Zvksh" Cryptography Extension for ShangMi Suite: Vector SM3 Secure Hash - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkn: "zvkn"; - /// "Zvkn" Cryptography Extension for NIST Algorithm Suite - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknc: "zvknc"; - /// "Zvknc" Cryptography Extension for NIST Algorithm Suite with Carryless Multiply - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkng: "zvkng"; - /// "Zvkng" Cryptography Extension for NIST Algorithm Suite with GCM - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvks: "zvks"; - /// "Zvks" Cryptography Extension for ShangMi Algorithm Suite - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksc: "zvksc"; - /// "Zvksc" Cryptography Extension for ShangMi Algorithm Suite with Carryless Multiply - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksg: "zvksg"; - /// "Zvksg" Cryptography Extension for ShangMi Algorithm Suite with GCM - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkt: "zvkt"; - /// "Zvkt" Extension for Vector Data-Independent Execution Latency - - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] j: "j"; - without cfg check: true; - /// "J" Extension for Dynamically Translated Languages - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] p: "p"; - without cfg check: true; - /// "P" Extension for Packed-SIMD Instructions -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/s390x.rs b/library/stdarch/crates/std_detect/src/detect/arch/s390x.rs deleted file mode 100644 index 4c20d011680..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/s390x.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Run-time feature detection on s390x. - -features! { - @TARGET: s390x; - @CFG: target_arch = "s390x"; - @MACRO_NAME: is_s390x_feature_detected; - @MACRO_ATTRS: - /// Checks if `s390x` feature is enabled. - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] concurrent_functions: "concurrent-functions"; - /// s390x concurrent-functions facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] deflate_conversion: "deflate-conversion"; - /// s390x deflate-conversion facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] enhanced_sort: "enhanced-sort"; - /// s390x enhanced-sort facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] guarded_storage: "guarded-storage"; - /// s390x guarded-storage facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] high_word: "high-word"; - /// s390x high-word facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension3: "message-security-assist-extension3"; - /// s390x message-security-assist-extension3 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension4: "message-security-assist-extension4"; - /// s390x message-security-assist-extension4 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension5: "message-security-assist-extension5"; - /// s390x message-security-assist-extension5 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension8: "message-security-assist-extension8"; - /// s390x message-security-assist-extension8 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension9: "message-security-assist-extension9"; - /// s390x message-security-assist-extension9 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] message_security_assist_extension12: "message-security-assist-extension12"; - /// s390x message-security-assist-extension12 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] miscellaneous_extensions_2: "miscellaneous-extensions-2"; - /// s390x miscellaneous-extensions-2 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] miscellaneous_extensions_3: "miscellaneous-extensions-3"; - /// s390x miscellaneous-extensions-3 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] miscellaneous_extensions_4: "miscellaneous-extensions-4"; - /// s390x miscellaneous-extensions-4 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] nnp_assist: "nnp-assist"; - /// s390x nnp-assist facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] transactional_execution: "transactional-execution"; - /// s390x transactional-execution facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector: "vector"; - /// s390x vector facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_enhancements_1: "vector-enhancements-1"; - /// s390x vector-enhancements-1 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_enhancements_2: "vector-enhancements-2"; - /// s390x vector-enhancements-2 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_enhancements_3: "vector-enhancements-3"; - /// s390x vector-enhancements-3 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal: "vector-packed-decimal"; - /// s390x vector-packed-decimal facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal_enhancement: "vector-packed-decimal-enhancement"; - /// s390x vector-packed-decimal-enhancement facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal_enhancement_2: "vector-packed-decimal-enhancement-2"; - /// s390x vector-packed-decimal-enhancement-2 facility - #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] - @FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] vector_packed_decimal_enhancement_3: "vector-packed-decimal-enhancement-3"; - /// s390x vector-packed-decimal-enhancement-3 facility -} diff --git a/library/stdarch/crates/std_detect/src/detect/arch/x86.rs b/library/stdarch/crates/std_detect/src/detect/arch/x86.rs deleted file mode 100644 index 28b3e3cfb35..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/arch/x86.rs +++ /dev/null @@ -1,278 +0,0 @@ -//! This module implements minimal run-time feature detection for x86. -//! -//! The features are detected using the `detect_features` function below. -//! This function uses the CPUID instruction to read the feature flags from the -//! CPU and encodes them in a `usize` where each bit position represents -//! whether a feature is available (bit is set) or unavailable (bit is cleared). -//! -//! The enum `Feature` is used to map bit positions to feature names, and the -//! the `__crate::detect::check_for!` macro is used to map string literals (e.g., -//! "avx") to these bit positions (e.g., `Feature::avx`). -//! -//! The run-time feature detection is performed by the -//! `__crate::detect::check_for(Feature) -> bool` function. On its first call, -//! this functions queries the CPU for the available features and stores them -//! in a global `AtomicUsize` variable. The query is performed by just checking -//! whether the feature bit in this global variable is set or cleared. - -features! { - @TARGET: x86; - @CFG: any(target_arch = "x86", target_arch = "x86_64"); - @MACRO_NAME: is_x86_feature_detected; - @MACRO_ATTRS: - /// A macro to test at *runtime* whether a CPU feature is available on - /// x86/x86-64 platforms. - /// - /// This macro is provided in the standard library and will detect at runtime - /// whether the specified CPU feature is detected. This does **not** resolve at - /// compile time unless the specified feature is already enabled for the entire - /// crate. Runtime detection currently relies mostly on the `cpuid` instruction. - /// - /// This macro only takes one argument which is a string literal of the feature - /// being tested for. The feature names supported are the lowercase versions of - /// the ones defined by Intel in [their documentation][docs]. - /// - /// ## Supported arguments - /// - /// This macro supports the same names that `#[target_feature]` supports. Unlike - /// `#[target_feature]`, however, this macro does not support names separated - /// with a comma. Instead testing for multiple features must be done through - /// separate macro invocations for now. - /// - /// Supported arguments are: - /// - /// * `"aes"` - /// * `"pclmulqdq"` - /// * `"rdrand"` - /// * `"rdseed"` - /// * `"tsc"` - /// * `"mmx"` - /// * `"sse"` - /// * `"sse2"` - /// * `"sse3"` - /// * `"ssse3"` - /// * `"sse4.1"` - /// * `"sse4.2"` - /// * `"sse4a"` - /// * `"sha"` - /// * `"avx"` - /// * `"avx2"` - /// * `"sha512"` - /// * `"sm3"` - /// * `"sm4"` - /// * `"avx512f"` - /// * `"avx512cd"` - /// * `"avx512er"` - /// * `"avx512pf"` - /// * `"avx512bw"` - /// * `"avx512dq"` - /// * `"avx512vl"` - /// * `"avx512ifma"` - /// * `"avx512vbmi"` - /// * `"avx512vpopcntdq"` - /// * `"avx512vbmi2"` - /// * `"gfni"` - /// * `"vaes"` - /// * `"vpclmulqdq"` - /// * `"avx512vnni"` - /// * `"avx512bitalg"` - /// * `"avx512bf16"` - /// * `"avx512vp2intersect"` - /// * `"avx512fp16"` - /// * `"avxvnni"` - /// * `"avxifma"` - /// * `"avxneconvert"` - /// * `"avxvnniint8"` - /// * `"avxvnniint16"` - /// * `"amx-tile"` - /// * `"amx-int8"` - /// * `"amx-bf16"` - /// * `"amx-fp16"` - /// * `"amx-complex"` - /// * `"amx-avx512"` - /// * `"amx-fp8"` - /// * `"amx-movrs"` - /// * `"amx-tf32"` - /// * `"amx-transpose"` - /// * `"f16c"` - /// * `"fma"` - /// * `"bmi1"` - /// * `"bmi2"` - /// * `"abm"` - /// * `"lzcnt"` - /// * `"tbm"` - /// * `"popcnt"` - /// * `"fxsr"` - /// * `"xsave"` - /// * `"xsaveopt"` - /// * `"xsaves"` - /// * `"xsavec"` - /// * `"cmpxchg16b"` - /// * `"kl"` - /// * `"widekl"` - /// * `"adx"` - /// * `"rtm"` - /// * `"movbe"` - /// * `"ermsb"` - /// * `"movrs"` - /// * `"xop"` - /// - /// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide - #[stable(feature = "simd_x86", since = "1.27.0")] - @BIND_FEATURE_NAME: "abm"; "lzcnt"; // abm is a synonym for lzcnt - @BIND_FEATURE_NAME: "avx512gfni"; "gfni"; #[deprecated(since = "1.67.0", note = "the `avx512gfni` feature has been renamed to `gfni`")]; - @BIND_FEATURE_NAME: "avx512vaes"; "vaes"; #[deprecated(since = "1.67.0", note = "the `avx512vaes` feature has been renamed to `vaes`")]; - @BIND_FEATURE_NAME: "avx512vpclmulqdq"; "vpclmulqdq"; #[deprecated(since = "1.67.0", note = "the `avx512vpclmulqdq` feature has been renamed to `vpclmulqdq`")]; - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] aes: "aes"; - /// AES (Advanced Encryption Standard New Instructions AES-NI) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] pclmulqdq: "pclmulqdq"; - /// CLMUL (Carry-less Multiplication) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rdrand: "rdrand"; - /// RDRAND - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rdseed: "rdseed"; - /// RDSEED - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] tsc: "tsc"; - without cfg check: true; - /// TSC (Time Stamp Counter) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] mmx: "mmx"; - without cfg check: true; - /// MMX (MultiMedia eXtensions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse: "sse"; - /// SSE (Streaming SIMD Extensions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse2: "sse2"; - /// SSE2 (Streaming SIMD Extensions 2) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse3: "sse3"; - /// SSE3 (Streaming SIMD Extensions 3) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] ssse3: "ssse3"; - /// SSSE3 (Supplemental Streaming SIMD Extensions 3) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4_1: "sse4.1"; - /// SSE4.1 (Streaming SIMD Extensions 4.1) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4_2: "sse4.2"; - /// SSE4.2 (Streaming SIMD Extensions 4.2) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4a: "sse4a"; - /// SSE4a (Streaming SIMD Extensions 4a) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sha: "sha"; - /// SHA - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx: "avx"; - /// AVX (Advanced Vector Extensions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx2: "avx2"; - /// AVX2 (Advanced Vector Extensions 2) - @FEATURE: #[stable(feature = "sha512_sm_x86", since = "1.89.0")] sha512: "sha512"; - /// SHA512 - @FEATURE: #[stable(feature = "sha512_sm_x86", since = "1.89.0")] sm3: "sm3"; - /// SM3 - @FEATURE: #[stable(feature = "sha512_sm_x86", since = "1.89.0")] sm4: "sm4"; - /// SM4 - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512f: "avx512f" ; - /// AVX-512 F (Foundation) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512cd: "avx512cd" ; - /// AVX-512 CD (Conflict Detection Instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512er: "avx512er"; - without cfg check: true; - /// AVX-512 ER (Expo nential and Reciprocal Instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512pf: "avx512pf"; - without cfg check: true; - /// AVX-512 PF (Prefetch Instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512bw: "avx512bw"; - /// AVX-512 BW (Byte and Word Instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512dq: "avx512dq"; - /// AVX-512 DQ (Doubleword and Quadword) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vl: "avx512vl"; - /// AVX-512 VL (Vector Length Extensions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512ifma: "avx512ifma"; - /// AVX-512 IFMA (Integer Fused Multiply Add) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vbmi: "avx512vbmi"; - /// AVX-512 VBMI (Vector Byte Manipulation Instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vpopcntdq: "avx512vpopcntdq"; - /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and Quadword) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vbmi2: "avx512vbmi2"; - /// AVX-512 VBMI2 (Additional byte, word, dword and qword capabilities) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] gfni: "gfni"; - /// AVX-512 GFNI (Galois Field New Instruction) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] vaes: "vaes"; - /// AVX-512 VAES (Vector AES instruction) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] vpclmulqdq: "vpclmulqdq"; - /// AVX-512 VPCLMULQDQ (Vector PCLMULQDQ instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vnni: "avx512vnni"; - /// AVX-512 VNNI (Vector Neural Network Instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512bitalg: "avx512bitalg"; - /// AVX-512 BITALG (Support for VPOPCNT\[B,W\] and VPSHUFBITQMB) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512bf16: "avx512bf16"; - /// AVX-512 BF16 (BFLOAT16 instructions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512vp2intersect: "avx512vp2intersect"; - /// AVX-512 P2INTERSECT - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx512fp16: "avx512fp16"; - /// AVX-512 FP16 (FLOAT16 instructions) - @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxifma: "avxifma"; - /// AVX-IFMA (Integer Fused Multiply Add) - @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxneconvert: "avxneconvert"; - /// AVX-NE-CONVERT (Exceptionless Convert) - @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxvnni: "avxvnni"; - /// AVX-VNNI (Vector Neural Network Instructions) - @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxvnniint16: "avxvnniint16"; - /// AVX-VNNI_INT8 (VNNI with 16-bit Integers) - @FEATURE: #[stable(feature = "avx512_target_feature", since = "1.89.0")] avxvnniint8: "avxvnniint8"; - /// AVX-VNNI_INT16 (VNNI with 8-bit integers) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_tile: "amx-tile"; - /// AMX (Advanced Matrix Extensions) - Tile load/store - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_int8: "amx-int8"; - /// AMX-INT8 (Operations on 8-bit integers) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_bf16: "amx-bf16"; - /// AMX-BF16 (BFloat16 Operations) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_fp16: "amx-fp16"; - /// AMX-FP16 (Float16 Operations) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_complex: "amx-complex"; - /// AMX-COMPLEX (Complex number Operations) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_avx512: "amx-avx512"; - /// AMX-AVX512 (AVX512 operations extended to matrices) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_fp8: "amx-fp8"; - /// AMX-FP8 (Float8 Operations) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_movrs: "amx-movrs"; - /// AMX-MOVRS (Matrix MOVERS operations) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_tf32: "amx-tf32"; - /// AMX-TF32 (TensorFloat32 Operations) - @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_transpose: "amx-transpose"; - /// AMX-TRANSPOSE (Matrix Transpose Operations) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] f16c: "f16c"; - /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fma: "fma"; - /// FMA (Fused Multiply Add) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] bmi1: "bmi1" ; - /// BMI1 (Bit Manipulation Instructions 1) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] bmi2: "bmi2" ; - /// BMI2 (Bit Manipulation Instructions 2) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] lzcnt: "lzcnt"; - /// ABM (Advanced Bit Manipulation) / LZCNT (Leading Zero Count) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] tbm: "tbm"; - /// TBM (Trailing Bit Manipulation) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] popcnt: "popcnt"; - /// POPCNT (Population Count) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fxsr: "fxsr"; - /// FXSR (Floating-point context fast save and restore) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsave: "xsave"; - /// XSAVE (Save Processor Extended States) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsaveopt: "xsaveopt"; - /// XSAVEOPT (Save Processor Extended States Optimized) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsaves: "xsaves"; - /// XSAVES (Save Processor Extended States Supervisor) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsavec: "xsavec"; - /// XSAVEC (Save Processor Extended States Compacted) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] cmpxchg16b: "cmpxchg16b"; - /// CMPXCH16B (16-byte compare-and-swap instruction) - @FEATURE: #[stable(feature = "keylocker_x86", since = "1.89.0")] kl: "kl"; - /// Intel Key Locker - @FEATURE: #[stable(feature = "keylocker_x86", since = "1.89.0")] widekl: "widekl"; - /// Intel Key Locker Wide - @FEATURE: #[stable(feature = "simd_x86_adx", since = "1.33.0")] adx: "adx"; - /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rtm: "rtm"; - /// RTM, Intel (Restricted Transactional Memory) - @FEATURE: #[stable(feature = "movbe_target_feature", since = "1.67.0")] movbe: "movbe"; - /// MOVBE (Move Data After Swapping Bytes) - @FEATURE: #[unstable(feature = "movrs_target_feature", issue = "137976")] movrs: "movrs"; - /// MOVRS (Move data with the read-shared hint) - @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] ermsb: "ermsb"; - /// ERMSB, Enhanced REP MOVSB and STOSB - @FEATURE: #[unstable(feature = "xop_target_feature", issue = "127208")] xop: "xop"; - /// XOP: eXtended Operations (AMD) -} diff --git a/library/stdarch/crates/std_detect/src/detect/bit.rs b/library/stdarch/crates/std_detect/src/detect/bit.rs deleted file mode 100644 index 6f06c5523e4..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/bit.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Bit manipulation utilities. - -/// Tests the `bit` of `x`. -#[allow(dead_code)] -#[inline] -pub(crate) fn test(x: usize, bit: u32) -> bool { - debug_assert!(bit < usize::BITS, "bit index out-of-bounds"); - x & (1 << bit) != 0 -} diff --git a/library/stdarch/crates/std_detect/src/detect/cache.rs b/library/stdarch/crates/std_detect/src/detect/cache.rs deleted file mode 100644 index 83bcedea612..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/cache.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! Caches run-time feature detection so that it only needs to be computed -//! once. - -#![allow(dead_code)] // not used on all platforms - -use core::sync::atomic::Ordering; - -use core::sync::atomic::AtomicUsize; - -/// Sets the `bit` of `x`. -#[inline] -const fn set_bit(x: u128, bit: u32) -> u128 { - x | 1 << bit -} - -/// Tests the `bit` of `x`. -#[inline] -const fn test_bit(x: u128, bit: u32) -> bool { - x & (1 << bit) != 0 -} - -/// Unset the `bit of `x`. -#[inline] -const fn unset_bit(x: u128, bit: u32) -> u128 { - x & !(1 << bit) -} - -/// Maximum number of features that can be cached. -const CACHE_CAPACITY: u32 = 93; - -/// This type is used to initialize the cache -// The derived `Default` implementation will initialize the field to zero, -// which is what we want. -#[derive(Copy, Clone, Default, PartialEq, Eq)] -pub(crate) struct Initializer(u128); - -// NOTE: the `debug_assert!` would catch that we do not add more Features than -// the one fitting our cache. -impl Initializer { - /// Tests the `bit` of the cache. - #[inline] - pub(crate) fn test(self, bit: u32) -> bool { - debug_assert!( - bit < CACHE_CAPACITY, - "too many features, time to increase the cache size!" - ); - test_bit(self.0, bit) - } - - /// Sets the `bit` of the cache. - #[inline] - pub(crate) fn set(&mut self, bit: u32) { - debug_assert!( - bit < CACHE_CAPACITY, - "too many features, time to increase the cache size!" - ); - let v = self.0; - self.0 = set_bit(v, bit); - } - - /// Unsets the `bit` of the cache. - #[inline] - pub(crate) fn unset(&mut self, bit: u32) { - debug_assert!( - bit < CACHE_CAPACITY, - "too many features, time to increase the cache size!" - ); - let v = self.0; - self.0 = unset_bit(v, bit); - } -} - -/// This global variable is a cache of the features supported by the CPU. -// Note: the third slot is only used in x86 -// Another Slot can be added if needed without any change to `Initializer` -static CACHE: [Cache; 3] = [ - Cache::uninitialized(), - Cache::uninitialized(), - Cache::uninitialized(), -]; - -/// Feature cache with capacity for `size_of::() * 8 - 1` features. -/// -/// Note: 0 is used to represent an uninitialized cache, and (at least) the most -/// significant bit is set on any cache which has been initialized. -/// -/// Note: we use `Relaxed` atomic operations, because we are only interested in -/// the effects of operations on a single memory location. That is, we only need -/// "modification order", and not the full-blown "happens before". -struct Cache(AtomicUsize); - -impl Cache { - const CAPACITY: u32 = (core::mem::size_of::() * 8 - 1) as u32; - const MASK: usize = (1 << Cache::CAPACITY) - 1; - const INITIALIZED_BIT: usize = 1usize << Cache::CAPACITY; - - /// Creates an uninitialized cache. - #[allow(clippy::declare_interior_mutable_const)] - const fn uninitialized() -> Self { - Cache(AtomicUsize::new(0)) - } - - /// Is the `bit` in the cache set? Returns `None` if the cache has not been initialized. - #[inline] - pub(crate) fn test(&self, bit: u32) -> Option { - let cached = self.0.load(Ordering::Relaxed); - if cached == 0 { - None - } else { - Some(test_bit(cached as u128, bit)) - } - } - - /// Initializes the cache. - #[inline] - fn initialize(&self, value: usize) -> usize { - debug_assert_eq!((value & !Cache::MASK), 0); - self.0 - .store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed); - value - } -} - -cfg_if::cfg_if! { - if #[cfg(feature = "std_detect_env_override")] { - #[inline] - fn disable_features(disable: &[u8], value: &mut Initializer) { - if let Ok(disable) = core::str::from_utf8(disable) { - for v in disable.split(" ") { - let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32)); - } - } - } - - #[inline] - fn initialize(mut value: Initializer) -> Initializer { - use core::ffi::CStr; - const RUST_STD_DETECT_UNSTABLE: &CStr = c"RUST_STD_DETECT_UNSTABLE"; - cfg_if::cfg_if! { - if #[cfg(windows)] { - use alloc::vec; - #[link(name = "kernel32")] - unsafe extern "system" { - fn GetEnvironmentVariableA(name: *const u8, buffer: *mut u8, size: u32) -> u32; - } - let len = unsafe { GetEnvironmentVariableA(RUST_STD_DETECT_UNSTABLE.as_ptr().cast::(), core::ptr::null_mut(), 0) }; - if len > 0 { - // +1 to include the null terminator. - let mut env = vec![0; len as usize + 1]; - let len = unsafe { GetEnvironmentVariableA(RUST_STD_DETECT_UNSTABLE.as_ptr().cast::(), env.as_mut_ptr(), len + 1) }; - if len > 0 { - disable_features(&env[..len as usize], &mut value); - } - } - } else { - let env = unsafe { - libc::getenv(RUST_STD_DETECT_UNSTABLE.as_ptr()) - }; - if !env.is_null() { - let len = unsafe { libc::strlen(env) }; - let env = unsafe { core::slice::from_raw_parts(env as *const u8, len) }; - disable_features(env, &mut value); - } - } - } - do_initialize(value); - value - } - } else { - #[inline] - fn initialize(value: Initializer) -> Initializer { - do_initialize(value); - value - } - } -} - -#[inline] -fn do_initialize(value: Initializer) { - CACHE[0].initialize((value.0) as usize & Cache::MASK); - CACHE[1].initialize((value.0 >> Cache::CAPACITY) as usize & Cache::MASK); - CACHE[2].initialize((value.0 >> (2 * Cache::CAPACITY)) as usize & Cache::MASK); -} - -// We only have to detect features once, and it's fairly costly, so hint to LLVM -// that it should assume that cache hits are more common than misses (which is -// the point of caching). It's possibly unfortunate that this function needs to -// reach across modules like this to call `os::detect_features`, but it produces -// the best code out of several attempted variants. -// -// The `Initializer` that the cache was initialized with is returned, so that -// the caller can call `test()` on it without having to load the value from the -// cache again. -#[cold] -fn detect_and_initialize() -> Initializer { - initialize(super::os::detect_features()) -} - -/// Tests the `bit` of the storage. If the storage has not been initialized, -/// initializes it with the result of `os::detect_features()`. -/// -/// On its first invocation, it detects the CPU features and caches them in the -/// `CACHE` global variable as an `AtomicU64`. -/// -/// It uses the `Feature` variant to index into this variable as a bitset. If -/// the bit is set, the feature is enabled, and otherwise it is disabled. -/// -/// If the feature `std_detect_env_override` is enabled looks for the env -/// variable `RUST_STD_DETECT_UNSTABLE` and uses its content to disable -/// Features that would had been otherwise detected. -#[inline] -pub(crate) fn test(bit: u32) -> bool { - let (relative_bit, idx) = if bit < Cache::CAPACITY { - (bit, 0) - } else if bit < 2 * Cache::CAPACITY { - (bit - Cache::CAPACITY, 1) - } else { - (bit - 2 * Cache::CAPACITY, 2) - }; - CACHE[idx] - .test(relative_bit) - .unwrap_or_else(|| detect_and_initialize().test(bit)) -} diff --git a/library/stdarch/crates/std_detect/src/detect/macros.rs b/library/stdarch/crates/std_detect/src/detect/macros.rs deleted file mode 100644 index a2994fb7daa..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/macros.rs +++ /dev/null @@ -1,204 +0,0 @@ -#[macro_export] -#[allow_internal_unstable(stdarch_internal)] -#[unstable(feature = "stdarch_internal", issue = "none")] -macro_rules! detect_feature { - ($feature:tt, $feature_lit:tt) => { - $crate::detect_feature!($feature, $feature_lit : $feature_lit) - }; - ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { - $(cfg!(target_feature = $target_feature_lit) ||)* - $crate::detect::__is_feature_detected::$feature() - }; - ($feature:tt, $feature_lit:tt, without cfg check: true) => { - $crate::detect::__is_feature_detected::$feature() - }; -} - -#[allow(unused_macros, reason = "it's used in the features! macro below")] -macro_rules! check_cfg_feature { - ($feature:tt, $feature_lit:tt) => { - check_cfg_feature!($feature, $feature_lit : $feature_lit) - }; - ($feature:tt, $feature_lit:tt : $($target_feature_lit:tt),*) => { - $(cfg!(target_feature = $target_feature_lit);)* - }; - ($feature:tt, $feature_lit:tt, without cfg check: $feature_cfg_check:literal) => { - #[allow(unexpected_cfgs, reason = $feature_lit)] - { cfg!(target_feature = $feature_lit) } - }; -} - -#[allow(unused)] -macro_rules! features { - ( - @TARGET: $target:ident; - @CFG: $cfg:meta; - @MACRO_NAME: $macro_name:ident; - @MACRO_ATTRS: $(#[$macro_attrs:meta])* - $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; $(#[$deprecate_attr:meta];)?)* - $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )* - $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; - $(without cfg check: $feature_cfg_check:tt;)? - $(implied by target_features: [$($target_feature_lit:tt),*];)? - $(#[$feature_comment:meta])*)* - ) => { - #[macro_export] - $(#[$macro_attrs])* - #[allow_internal_unstable(stdarch_internal)] - #[cfg($cfg)] - #[doc(cfg($cfg))] - macro_rules! $macro_name { - $( - ($feature_lit) => { - $crate::detect_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?) - }; - )* - $( - ($bind_feature) => { - { - $( - #[$deprecate_attr] macro_rules! deprecated_feature { {} => {}; } - deprecated_feature! {}; - )? - $crate::$macro_name!($feature_impl) - } - }; - )* - $( - ($nort_feature) => { - compile_error!( - concat!( - stringify!($nort_feature), - " feature cannot be detected at run-time" - ) - ) - }; - )* - ($t:tt,) => { - $crate::$macro_name!($t); - }; - ($t:tt) => { - compile_error!( - concat!( - concat!("unknown ", stringify!($target)), - concat!(" target feature: ", $t) - ) - ) - }; - } - - $(#[$macro_attrs])* - #[macro_export] - #[cfg(not($cfg))] - #[doc(cfg($cfg))] - macro_rules! $macro_name { - $( - ($feature_lit) => { - compile_error!( - concat!( - r#"This macro cannot be used on the current target. - You can prevent it from being used in other architectures by - guarding it behind a cfg("#, - stringify!($cfg), - ")." - ) - ) - }; - )* - $( - ($bind_feature) => { $crate::$macro_name!($feature_impl) }; - )* - $( - ($nort_feature) => { - compile_error!( - concat!( - stringify!($nort_feature), - " feature cannot be detected at run-time" - ) - ) - }; - )* - ($t:tt,) => { - $crate::$macro_name!($t); - }; - ($t:tt) => { - compile_error!( - concat!( - concat!("unknown ", stringify!($target)), - concat!(" target feature: ", $t) - ) - ) - }; - } - - #[test] - #[deny(unexpected_cfgs)] - #[deny(unfulfilled_lint_expectations)] - fn unexpected_cfgs() { - $( - check_cfg_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?); - )* - } - - /// Each variant denotes a position in a bitset for a particular feature. - /// - /// PLEASE: do not use this, it is an implementation detail subject - /// to change. - #[doc(hidden)] - #[allow(non_camel_case_types)] - #[derive(Copy, Clone)] - #[repr(u8)] - #[unstable(feature = "stdarch_internal", issue = "none")] - #[cfg($cfg)] - pub(crate) enum Feature { - $( - $(#[$feature_comment])* - $feature, - )* - - // Do not add variants after last: - _last - } - - #[cfg($cfg)] - impl Feature { - pub(crate) fn to_str(self) -> &'static str { - match self { - $(Feature::$feature => $feature_lit,)* - Feature::_last => unreachable!(), - } - } - - #[cfg(feature = "std_detect_env_override")] - pub(crate) fn from_str(s: &str) -> Result { - match s { - $($feature_lit => Ok(Feature::$feature),)* - _ => Err(()) - } - } - } - - /// Each function performs run-time feature detection for a single - /// feature. This allow us to use stability attributes on a per feature - /// basis. - /// - /// PLEASE: do not use this, it is an implementation detail subject - /// to change. - #[doc(hidden)] - #[cfg($cfg)] - #[unstable(feature = "stdarch_internal", issue = "none")] - pub mod __is_feature_detected { - $( - - /// PLEASE: do not use this, it is an implementation detail - /// subject to change. - #[inline] - #[doc(hidden)] - #[$stability_attr] - pub fn $feature() -> bool { - $crate::detect::check_for($crate::detect::Feature::$feature) - } - )* - } - }; -} diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs deleted file mode 100644 index a9e9709c1f6..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/mod.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! This module implements run-time feature detection. -//! -//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a -//! feature as a string-literal, and return a boolean indicating whether the -//! feature is enabled at run-time or not. -//! -//! These macros do two things: -//! * map the string-literal into an integer stored as a `Feature` enum, -//! * call a `os::check_for(x: Feature)` function that returns `true` if the -//! feature is enabled. -//! -//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs` -//! modules. -//! -//! The `check_for` functions are, in general, Operating System dependent. Most -//! architectures do not allow user-space programs to query the feature bits -//! due to security concerns (x86 is the big exception). These functions are -//! implemented in the `os/{target_os}.rs` modules. - -use cfg_if::cfg_if; - -#[macro_use] -mod macros; - -mod arch; - -// This module needs to be public because the `is_{arch}_feature_detected!` -// macros expand calls to items within it in user crates. -#[doc(hidden)] -#[unstable(feature = "stdarch_internal", issue = "none")] -pub use self::arch::__is_feature_detected; - -pub(crate) use self::arch::Feature; - -mod bit; -mod cache; - -cfg_if! { - if #[cfg(miri)] { - // When running under miri all target-features that are not enabled at - // compile-time are reported as disabled at run-time. - // - // For features for which `cfg(target_feature)` returns true, - // this run-time detection logic is never called. - #[path = "os/other.rs"] - mod os; - } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - // On x86/x86_64 no OS specific functionality is required. - #[path = "os/x86.rs"] - mod os; - } else if #[cfg(all(any(target_os = "linux", target_os = "android"), feature = "libc"))] { - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] - #[path = "os/riscv.rs"] - mod riscv; - #[path = "os/linux/mod.rs"] - mod os; - } else if #[cfg(all(target_os = "freebsd", feature = "libc"))] { - #[cfg(target_arch = "aarch64")] - #[path = "os/aarch64.rs"] - mod aarch64; - #[path = "os/freebsd/mod.rs"] - mod os; - } else if #[cfg(all(target_os = "openbsd", target_arch = "aarch64", feature = "libc"))] { - #[allow(dead_code)] // we don't use code that calls the mrs instruction. - #[path = "os/aarch64.rs"] - mod aarch64; - #[path = "os/openbsd/aarch64.rs"] - mod os; - } else if #[cfg(all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")))] { - #[path = "os/windows/aarch64.rs"] - mod os; - } else if #[cfg(all(target_vendor = "apple", target_arch = "aarch64", feature = "libc"))] { - #[path = "os/darwin/aarch64.rs"] - mod os; - } else { - #[path = "os/other.rs"] - mod os; - } -} - -/// Performs run-time feature detection. -#[inline] -#[allow(dead_code)] -fn check_for(x: Feature) -> bool { - cache::test(x as u32) -} - -/// Returns an `Iterator` where -/// `Item.0` is the feature name, and `Item.1` is a `bool` which -/// is `true` if the feature is supported by the host and `false` otherwise. -#[unstable(feature = "stdarch_internal", issue = "none")] -pub fn features() -> impl Iterator { - cfg_if! { - if #[cfg(any( - target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "arm64ec", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "mips", - target_arch = "mips64", - target_arch = "loongarch32", - target_arch = "loongarch64", - target_arch = "s390x", - ))] { - (0_u8..Feature::_last as u8).map(|discriminant: u8| { - #[allow(bindings_with_variant_name)] // RISC-V has Feature::f - let f: Feature = unsafe { core::mem::transmute(discriminant) }; - let name: &'static str = f.to_str(); - let enabled: bool = check_for(f); - (name, enabled) - }) - } else { - None.into_iter() - } - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs deleted file mode 100644 index 1ff2a17e6e1..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction. -//! -//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use -//! privileged system registers from userspace to check CPU feature support. -//! -//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1 -//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc. -//! Each part of the register indicates the level of support for a certain feature, e.g. -//! when ID_AA64ISAR0_EL1\[7:4\] is >= 1, AES is supported; when it's >= 2, PMULL is supported. -//! -//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb), -//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947). -//! -//! References: -//! -//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp) -//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt) -//! - [ARM documentation](https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers?lang=en) - -use crate::detect::{Feature, cache}; -use core::arch::asm; - -/// Try to read the features from the system registers. -/// -/// This will cause SIGILL if the current OS is not trapping the mrs instruction. -pub(crate) fn detect_features() -> cache::Initializer { - // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 - let aa64isar0: u64; - unsafe { - asm!( - "mrs {}, ID_AA64ISAR0_EL1", - out(reg) aa64isar0, - options(pure, nomem, preserves_flags, nostack) - ); - } - - // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1 - let aa64isar1: u64; - unsafe { - asm!( - "mrs {}, ID_AA64ISAR1_EL1", - out(reg) aa64isar1, - options(pure, nomem, preserves_flags, nostack) - ); - } - - // ID_AA64MMFR2_EL1 - AArch64 Memory Model Feature Register 2 - let aa64mmfr2: u64; - unsafe { - asm!( - "mrs {}, ID_AA64MMFR2_EL1", - out(reg) aa64mmfr2, - options(pure, nomem, preserves_flags, nostack) - ); - } - - // ID_AA64PFR0_EL1 - Processor Feature Register 0 - let aa64pfr0: u64; - unsafe { - asm!( - "mrs {}, ID_AA64PFR0_EL1", - out(reg) aa64pfr0, - options(pure, nomem, preserves_flags, nostack) - ); - } - - parse_system_registers(aa64isar0, aa64isar1, aa64mmfr2, Some(aa64pfr0)) -} - -pub(crate) fn parse_system_registers( - aa64isar0: u64, - aa64isar1: u64, - aa64mmfr2: u64, - aa64pfr0: Option, -) -> cache::Initializer { - let mut value = cache::Initializer::default(); - - let mut enable_feature = |f, enable| { - if enable { - value.set(f as u32); - } - }; - - // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 - enable_feature(Feature::pmull, bits_shift(aa64isar0, 7, 4) >= 2); - enable_feature(Feature::tme, bits_shift(aa64isar0, 27, 24) == 1); - enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 2); - enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1); - - // ID_AA64PFR0_EL1 - Processor Feature Register 0 - if let Some(aa64pfr0) = aa64pfr0 { - let fp = bits_shift(aa64pfr0, 19, 16) < 0xF; - let fphp = bits_shift(aa64pfr0, 19, 16) >= 1; - let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF; - let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1; - enable_feature(Feature::fp, fp); - enable_feature(Feature::fp16, fphp); - // SIMD support requires float support - if half-floats are - // supported, it also requires half-float support: - enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp)); - // SIMD extensions require SIMD support: - enable_feature(Feature::aes, asimd && bits_shift(aa64isar0, 7, 4) >= 2); - let sha1 = bits_shift(aa64isar0, 11, 8) >= 1; - let sha2 = bits_shift(aa64isar0, 15, 12) >= 1; - enable_feature(Feature::sha2, asimd && sha1 && sha2); - enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1); - enable_feature( - Feature::dotprod, - asimd && bits_shift(aa64isar0, 47, 44) >= 1, - ); - enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1); - } - - // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1 - // Check for either APA or API field - enable_feature(Feature::paca, bits_shift(aa64isar1, 11, 4) >= 1); - enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1); - // Check for either GPA or GPI field - enable_feature(Feature::pacg, bits_shift(aa64isar1, 31, 24) >= 1); - - // ID_AA64MMFR2_EL1 - AArch64 Memory Model Feature Register 2 - enable_feature(Feature::lse2, bits_shift(aa64mmfr2, 35, 32) >= 1); - - value -} - -#[inline] -fn bits_shift(x: u64, high: usize, low: usize) -> u64 { - (x >> low) & ((1 << (high - low + 1)) - 1) -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/darwin/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/darwin/aarch64.rs deleted file mode 100644 index 44d921689e5..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/darwin/aarch64.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Run-time feature detection for aarch64 on Darwin (macOS/iOS/tvOS/watchOS/visionOS). -//! -//! - -use crate::detect::{Feature, cache}; -use core::ffi::CStr; - -#[inline] -fn _sysctlbyname(name: &CStr) -> bool { - use libc; - - let mut enabled: i32 = 0; - let mut enabled_len: usize = 4; - let enabled_ptr = &mut enabled as *mut i32 as *mut libc::c_void; - - let ret = unsafe { - libc::sysctlbyname( - name.as_ptr(), - enabled_ptr, - &mut enabled_len, - core::ptr::null_mut(), - 0, - ) - }; - - match ret { - 0 => enabled != 0, - _ => false, - } -} - -/// Try to read the features using sysctlbyname. -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - - let mut enable_feature = |f, enable| { - if enable { - value.set(f as u32); - } - }; - - // Armv8.0 features not using the standard identifiers - let fp = _sysctlbyname(c"hw.optional.floatingpoint"); - let asimd = _sysctlbyname(c"hw.optional.AdvSIMD"); - let crc = _sysctlbyname(c"hw.optional.armv8_crc32"); - - // Armv8 and Armv9 features using the standard identifiers - let aes = _sysctlbyname(c"hw.optional.arm.FEAT_AES"); - let bf16 = _sysctlbyname(c"hw.optional.arm.FEAT_BF16"); - let bti = _sysctlbyname(c"hw.optional.arm.FEAT_BTI"); - let cssc = _sysctlbyname(c"hw.optional.arm.FEAT_CSSC"); - let dit = _sysctlbyname(c"hw.optional.arm.FEAT_DIT"); - let dpb = _sysctlbyname(c"hw.optional.arm.FEAT_DPB"); - let dpb2 = _sysctlbyname(c"hw.optional.arm.FEAT_DPB2"); - let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd"); - let ecv = _sysctlbyname(c"hw.optional.arm.FEAT_ECV"); - let fcma = _sysctlbyname(c"hw.optional.arm.FEAT_FCMA"); - let fhm = _sysctlbyname(c"hw.optional.arm.FEAT_FHM"); - let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16"); - let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS"); - let flagm = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM"); - let flagm2 = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM2"); - let hbc = _sysctlbyname(c"hw.optional.arm.FEAT_HBC"); - let i8mm = _sysctlbyname(c"hw.optional.arm.FEAT_I8MM"); - let jsconv = _sysctlbyname(c"hw.optional.arm.FEAT_JSCVT"); - let rcpc = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC"); - let rcpc2 = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC2"); - let lse = _sysctlbyname(c"hw.optional.arm.FEAT_LSE"); - let lse2 = _sysctlbyname(c"hw.optional.arm.FEAT_LSE2"); - let pauth = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth"); - let pmull = _sysctlbyname(c"hw.optional.arm.FEAT_PMULL"); - let rdm = _sysctlbyname(c"hw.optional.arm.FEAT_RDM"); - let sb = _sysctlbyname(c"hw.optional.arm.FEAT_SB"); - let sha1 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA1"); - let sha256 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA256"); - let sha3 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA3"); - let sha512 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA512"); - let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME"); - let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2"); - let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64"); - let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64"); - let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS"); - let wfxt = _sysctlbyname(c"hw.optional.arm.FEAT_WFxT"); - - // The following features are not exposed by `is_aarch64_feature_detected`, - // but *are* reported by `sysctl`. They are here as documentation that they - // exist, and may potentially be exposed later. - /* - let afp = _sysctlbyname(c"hw.optional.arm.FEAT_AFP"); - let csv2 = _sysctlbyname(c"hw.optional.arm.FEAT_CSV2"); - let csv3 = _sysctlbyname(c"hw.optional.arm.FEAT_CSV3"); - let ebf16 = _sysctlbyname(c"hw.optional.arm.FEAT_EBF16"); - let fpac = _sysctlbyname(c"hw.optional.arm.FEAT_FPAC"); - let fpaccombine = _sysctlbyname(c"hw.optional.arm.FEAT_FPACCOMBINE"); - let pacimp = _sysctlbyname(c"hw.optional.arm.FEAT_PACIMP"); - let pauth2 = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth2"); - let rpres = _sysctlbyname(c"hw.optional.arm.FEAT_RPRES"); - let specres = _sysctlbyname(c"hw.optional.arm.FEAT_SPECRES"); - let specres2 = _sysctlbyname(c"hw.optional.arm.FEAT_SPECRES2"); - */ - - // The following "features" are reported by `sysctl` but are mandatory parts - // of SME or SME2, and so are not exposed separately by - // `is_aarch64_feature_detected`. They are here to document their - // existence, in case they're needed in the future. - /* - let sme_b16f32 = _sysctlbyname(c"hw.optional.arm.SME_B16F32"); - let sme_bi32i32 = _sysctlbyname(c"hw.optional.arm.SME_BI32I32"); - let sme_f16f32 = _sysctlbyname(c"hw.optional.arm.SME_F16F32"); - let sme_f32f32 = _sysctlbyname(c"hw.optional.arm.SME_F32F32"); - let sme_i16i32 = _sysctlbyname(c"hw.optional.arm.SME_I16I32"); - let sme_i8i32 = _sysctlbyname(c"hw.optional.arm.SME_I8I32"); - */ - - enable_feature(Feature::aes, aes && pmull); - enable_feature(Feature::asimd, asimd); - enable_feature(Feature::bf16, bf16); - enable_feature(Feature::bti, bti); - enable_feature(Feature::crc, crc); - enable_feature(Feature::cssc, cssc); - enable_feature(Feature::dit, dit); - enable_feature(Feature::dotprod, dotprod); - enable_feature(Feature::dpb, dpb); - enable_feature(Feature::dpb2, dpb2); - enable_feature(Feature::ecv, ecv); - enable_feature(Feature::fcma, fcma); - enable_feature(Feature::fhm, fhm); - enable_feature(Feature::flagm, flagm); - enable_feature(Feature::flagm2, flagm2); - enable_feature(Feature::fp, fp); - enable_feature(Feature::fp16, fp16); - enable_feature(Feature::frintts, frintts); - enable_feature(Feature::hbc, hbc); - enable_feature(Feature::i8mm, i8mm); - enable_feature(Feature::jsconv, jsconv); - enable_feature(Feature::lse, lse); - enable_feature(Feature::lse2, lse2); - enable_feature(Feature::paca, pauth); - enable_feature(Feature::pacg, pauth); - enable_feature(Feature::pmull, aes && pmull); - enable_feature(Feature::rcpc, rcpc); - enable_feature(Feature::rcpc2, rcpc2); - enable_feature(Feature::rdm, rdm); - enable_feature(Feature::sb, sb); - enable_feature(Feature::sha2, sha1 && sha256 && asimd); - enable_feature(Feature::sha3, sha512 && sha3 && asimd); - enable_feature(Feature::sme, sme); - enable_feature(Feature::sme2, sme2); - enable_feature(Feature::sme_f64f64, sme_f64f64); - enable_feature(Feature::sme_i16i64, sme_i16i64); - enable_feature(Feature::ssbs, ssbs); - enable_feature(Feature::wfxt, wfxt); - - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs deleted file mode 100644 index ccc48f53605..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Run-time feature detection for Aarch64 on FreeBSD. - -pub(crate) use super::super::aarch64::detect_features; diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs deleted file mode 100644 index 0a15156e1bd..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Run-time feature detection for ARM on FreeBSD - -use super::auxvec; -use crate::detect::{Feature, cache}; - -// Defined in machine/elf.h. -// https://github.com/freebsd/freebsd-src/blob/deb63adf945d446ed91a9d84124c71f15ae571d1/sys/arm/include/elf.h -const HWCAP_NEON: usize = 0x00001000; -const HWCAP2_AES: usize = 0x00000001; -const HWCAP2_PMULL: usize = 0x00000002; -const HWCAP2_SHA1: usize = 0x00000004; -const HWCAP2_SHA2: usize = 0x00000008; -const HWCAP2_CRC32: usize = 0x00000010; - -/// Try to read the features from the auxiliary vector -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let enable_feature = |value: &mut cache::Initializer, f, enable| { - if enable { - value.set(f as u32); - } - }; - - if let Ok(auxv) = auxvec::auxv() { - enable_feature(&mut value, Feature::neon, auxv.hwcap & HWCAP_NEON != 0); - enable_feature(&mut value, Feature::pmull, auxv.hwcap2 & HWCAP2_PMULL != 0); - enable_feature(&mut value, Feature::crc, auxv.hwcap2 & HWCAP2_CRC32 != 0); - enable_feature(&mut value, Feature::aes, auxv.hwcap2 & HWCAP2_AES != 0); - // SHA2 requires SHA1 & SHA2 features - let sha1 = auxv.hwcap2 & HWCAP2_SHA1 != 0; - let sha2 = auxv.hwcap2 & HWCAP2_SHA2 != 0; - enable_feature(&mut value, Feature::sha2, sha1 && sha2); - return value; - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs deleted file mode 100644 index 4e72bf22d76..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Parses ELF auxiliary vectors. -#![cfg_attr( - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "riscv64" - ), - allow(dead_code) -)] - -/// Cache HWCAP bitfields of the ELF Auxiliary Vector. -/// -/// If an entry cannot be read all the bits in the bitfield are set to zero. -/// This should be interpreted as all the features being disabled. -#[derive(Debug, Copy, Clone)] -pub(crate) struct AuxVec { - pub hwcap: usize, - pub hwcap2: usize, -} - -/// ELF Auxiliary Vector -/// -/// The auxiliary vector is a memory region in a running ELF program's stack -/// composed of (key: usize, value: usize) pairs. -/// -/// The keys used in the aux vector are platform dependent. For FreeBSD, they are -/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given -/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. -/// -/// Note that run-time feature detection is not invoked for features that can -/// be detected at compile-time. -/// -/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707 -pub(crate) fn auxv() -> Result { - let hwcap = archauxv(libc::AT_HWCAP); - let hwcap2 = archauxv(libc::AT_HWCAP2); - // Zero could indicate that no features were detected, but it's also used to - // indicate an error. In particular, on many platforms AT_HWCAP2 will be - // legitimately zero, since it contains the most recent feature flags. - if hwcap != 0 || hwcap2 != 0 { - return Ok(AuxVec { hwcap, hwcap2 }); - } - Err(()) -} - -/// Tries to read the `key` from the auxiliary vector. -fn archauxv(key: libc::c_int) -> usize { - const OUT_LEN: libc::c_int = core::mem::size_of::() as libc::c_int; - let mut out: libc::c_ulong = 0; - unsafe { - // elf_aux_info is available on FreeBSD 12.0+ and 11.4+: - // https://github.com/freebsd/freebsd-src/commit/0b08ae2120cdd08c20a2b806e2fcef4d0a36c470 - // https://github.com/freebsd/freebsd-src/blob/release/11.4.0/sys/sys/auxv.h - // FreeBSD 11 support in std has been removed in Rust 1.75 (https://github.com/rust-lang/rust/pull/114521), - // so we can safely use this function. - let res = libc::elf_aux_info( - key, - &mut out as *mut libc::c_ulong as *mut libc::c_void, - OUT_LEN, - ); - // If elf_aux_info fails, `out` will be left at zero (which is the proper default value). - debug_assert!(res == 0 || out == 0); - } - out as usize -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs deleted file mode 100644 index ade7fb6269d..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Run-time feature detection on FreeBSD - -mod auxvec; - -cfg_if::cfg_if! { - if #[cfg(target_arch = "aarch64")] { - mod aarch64; - pub(crate) use self::aarch64::detect_features; - } else if #[cfg(target_arch = "arm")] { - mod arm; - pub(crate) use self::arm::detect_features; - } else if #[cfg(target_arch = "powerpc64")] { - mod powerpc; - pub(crate) use self::powerpc::detect_features; - } else { - use crate::detect::cache; - /// Performs run-time feature detection. - pub(crate) fn detect_features() -> cache::Initializer { - cache::Initializer::default() - } - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs b/library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs deleted file mode 100644 index d03af68cd08..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Run-time feature detection for PowerPC on FreeBSD. - -use super::auxvec; -use crate::detect::{Feature, cache}; - -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let enable_feature = |value: &mut cache::Initializer, f, enable| { - if enable { - value.set(f as u32); - } - }; - - if let Ok(auxv) = auxvec::auxv() { - enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0); - enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0); - enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0); - return value; - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs deleted file mode 100644 index 22a9cefff7b..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs +++ /dev/null @@ -1,484 +0,0 @@ -//! Run-time feature detection for Aarch64 on Linux. - -use super::auxvec; -use crate::detect::{Feature, bit, cache}; - -/// Try to read the features from the auxiliary vector. -pub(crate) fn detect_features() -> cache::Initializer { - #[cfg(target_os = "android")] - let is_exynos9810 = { - // Samsung Exynos 9810 has a bug that big and little cores have different - // ISAs. And on older Android (pre-9), the kernel incorrectly reports - // that features available only on some cores are available on all cores. - // https://reviews.llvm.org/D114523 - let mut arch = [0_u8; libc::PROP_VALUE_MAX as usize]; - let len = unsafe { - libc::__system_property_get(c"ro.arch".as_ptr(), arch.as_mut_ptr() as *mut libc::c_char) - }; - // On Exynos, ro.arch is not available on Android 12+, but it is fine - // because Android 9+ includes the fix. - len > 0 && arch.starts_with(b"exynos9810") - }; - #[cfg(not(target_os = "android"))] - let is_exynos9810 = false; - - if let Ok(auxv) = auxvec::auxv() { - let hwcap: AtHwcap = auxv.into(); - return hwcap.cache(is_exynos9810); - } - cache::Initializer::default() -} - -/// These values are part of the platform-specific [asm/hwcap.h][hwcap] . -/// -/// The names match those used for cpuinfo. -/// -/// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h -#[derive(Debug, Default, PartialEq)] -struct AtHwcap { - // AT_HWCAP - fp: bool, - asimd: bool, - // evtstrm: No LLVM support. - aes: bool, - pmull: bool, - sha1: bool, - sha2: bool, - crc32: bool, - atomics: bool, - fphp: bool, - asimdhp: bool, - // cpuid: No LLVM support. - asimdrdm: bool, - jscvt: bool, - fcma: bool, - lrcpc: bool, - dcpop: bool, - sha3: bool, - sm3: bool, - sm4: bool, - asimddp: bool, - sha512: bool, - sve: bool, - fhm: bool, - dit: bool, - uscat: bool, - ilrcpc: bool, - flagm: bool, - ssbs: bool, - sb: bool, - paca: bool, - pacg: bool, - - // AT_HWCAP2 - dcpodp: bool, - sve2: bool, - sveaes: bool, - svepmull: bool, - svebitperm: bool, - svesha3: bool, - svesm4: bool, - flagm2: bool, - frint: bool, - // svei8mm: See i8mm feature. - svef32mm: bool, - svef64mm: bool, - // svebf16: See bf16 feature. - i8mm: bool, - bf16: bool, - // dgh: No LLVM support. - rng: bool, - bti: bool, - mte: bool, - ecv: bool, - // afp: bool, - // rpres: bool, - // mte3: bool, - sme: bool, - smei16i64: bool, - smef64f64: bool, - // smei8i32: bool, - // smef16f32: bool, - // smeb16f32: bool, - // smef32f32: bool, - smefa64: bool, - wfxt: bool, - // ebf16: bool, - // sveebf16: bool, - cssc: bool, - // rprfm: bool, - sve2p1: bool, - sme2: bool, - sme2p1: bool, - // smei16i32: bool, - // smebi32i32: bool, - smeb16b16: bool, - smef16f16: bool, - mops: bool, - hbc: bool, - sveb16b16: bool, - lrcpc3: bool, - lse128: bool, - fpmr: bool, - lut: bool, - faminmax: bool, - f8cvt: bool, - f8fma: bool, - f8dp4: bool, - f8dp2: bool, - f8e4m3: bool, - f8e5m2: bool, - smelutv2: bool, - smef8f16: bool, - smef8f32: bool, - smesf8fma: bool, - smesf8dp4: bool, - smesf8dp2: bool, - // pauthlr: bool, -} - -impl From for AtHwcap { - /// Reads AtHwcap from the auxiliary vector. - fn from(auxv: auxvec::AuxVec) -> Self { - AtHwcap { - fp: bit::test(auxv.hwcap, 0), - asimd: bit::test(auxv.hwcap, 1), - // evtstrm: bit::test(auxv.hwcap, 2), - aes: bit::test(auxv.hwcap, 3), - pmull: bit::test(auxv.hwcap, 4), - sha1: bit::test(auxv.hwcap, 5), - sha2: bit::test(auxv.hwcap, 6), - crc32: bit::test(auxv.hwcap, 7), - atomics: bit::test(auxv.hwcap, 8), - fphp: bit::test(auxv.hwcap, 9), - asimdhp: bit::test(auxv.hwcap, 10), - // cpuid: bit::test(auxv.hwcap, 11), - asimdrdm: bit::test(auxv.hwcap, 12), - jscvt: bit::test(auxv.hwcap, 13), - fcma: bit::test(auxv.hwcap, 14), - lrcpc: bit::test(auxv.hwcap, 15), - dcpop: bit::test(auxv.hwcap, 16), - sha3: bit::test(auxv.hwcap, 17), - sm3: bit::test(auxv.hwcap, 18), - sm4: bit::test(auxv.hwcap, 19), - asimddp: bit::test(auxv.hwcap, 20), - sha512: bit::test(auxv.hwcap, 21), - sve: bit::test(auxv.hwcap, 22), - fhm: bit::test(auxv.hwcap, 23), - dit: bit::test(auxv.hwcap, 24), - uscat: bit::test(auxv.hwcap, 25), - ilrcpc: bit::test(auxv.hwcap, 26), - flagm: bit::test(auxv.hwcap, 27), - ssbs: bit::test(auxv.hwcap, 28), - sb: bit::test(auxv.hwcap, 29), - paca: bit::test(auxv.hwcap, 30), - pacg: bit::test(auxv.hwcap, 31), - - // AT_HWCAP2 - dcpodp: bit::test(auxv.hwcap2, 0), - sve2: bit::test(auxv.hwcap2, 1), - sveaes: bit::test(auxv.hwcap2, 2), - svepmull: bit::test(auxv.hwcap2, 3), - svebitperm: bit::test(auxv.hwcap2, 4), - svesha3: bit::test(auxv.hwcap2, 5), - svesm4: bit::test(auxv.hwcap2, 6), - flagm2: bit::test(auxv.hwcap2, 7), - frint: bit::test(auxv.hwcap2, 8), - // svei8mm: bit::test(auxv.hwcap2, 9), - svef32mm: bit::test(auxv.hwcap2, 10), - svef64mm: bit::test(auxv.hwcap2, 11), - // svebf16: bit::test(auxv.hwcap2, 12), - i8mm: bit::test(auxv.hwcap2, 13), - bf16: bit::test(auxv.hwcap2, 14), - // dgh: bit::test(auxv.hwcap2, 15), - rng: bit::test(auxv.hwcap2, 16), - bti: bit::test(auxv.hwcap2, 17), - mte: bit::test(auxv.hwcap2, 18), - ecv: bit::test(auxv.hwcap2, 19), - // afp: bit::test(auxv.hwcap2, 20), - // rpres: bit::test(auxv.hwcap2, 21), - // mte3: bit::test(auxv.hwcap2, 22), - sme: bit::test(auxv.hwcap2, 23), - smei16i64: bit::test(auxv.hwcap2, 24), - smef64f64: bit::test(auxv.hwcap2, 25), - // smei8i32: bit::test(auxv.hwcap2, 26), - // smef16f32: bit::test(auxv.hwcap2, 27), - // smeb16f32: bit::test(auxv.hwcap2, 28), - // smef32f32: bit::test(auxv.hwcap2, 29), - smefa64: bit::test(auxv.hwcap2, 30), - wfxt: bit::test(auxv.hwcap2, 31), - // ebf16: bit::test(auxv.hwcap2, 32), - // sveebf16: bit::test(auxv.hwcap2, 33), - cssc: bit::test(auxv.hwcap2, 34), - // rprfm: bit::test(auxv.hwcap2, 35), - sve2p1: bit::test(auxv.hwcap2, 36), - sme2: bit::test(auxv.hwcap2, 37), - sme2p1: bit::test(auxv.hwcap2, 38), - // smei16i32: bit::test(auxv.hwcap2, 39), - // smebi32i32: bit::test(auxv.hwcap2, 40), - smeb16b16: bit::test(auxv.hwcap2, 41), - smef16f16: bit::test(auxv.hwcap2, 42), - mops: bit::test(auxv.hwcap2, 43), - hbc: bit::test(auxv.hwcap2, 44), - sveb16b16: bit::test(auxv.hwcap2, 45), - lrcpc3: bit::test(auxv.hwcap2, 46), - lse128: bit::test(auxv.hwcap2, 47), - fpmr: bit::test(auxv.hwcap2, 48), - lut: bit::test(auxv.hwcap2, 49), - faminmax: bit::test(auxv.hwcap2, 50), - f8cvt: bit::test(auxv.hwcap2, 51), - f8fma: bit::test(auxv.hwcap2, 52), - f8dp4: bit::test(auxv.hwcap2, 53), - f8dp2: bit::test(auxv.hwcap2, 54), - f8e4m3: bit::test(auxv.hwcap2, 55), - f8e5m2: bit::test(auxv.hwcap2, 56), - smelutv2: bit::test(auxv.hwcap2, 57), - smef8f16: bit::test(auxv.hwcap2, 58), - smef8f32: bit::test(auxv.hwcap2, 59), - smesf8fma: bit::test(auxv.hwcap2, 60), - smesf8dp4: bit::test(auxv.hwcap2, 61), - smesf8dp2: bit::test(auxv.hwcap2, 62), - // pauthlr: bit::test(auxv.hwcap2, ??), - } - } -} - -impl AtHwcap { - /// Initializes the cache from the feature -bits. - /// - /// The feature dependencies here come directly from LLVM's feature definitions: - /// https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AArch64/AArch64.td - fn cache(self, is_exynos9810: bool) -> cache::Initializer { - let mut value = cache::Initializer::default(); - { - let mut enable_feature = |f, enable| { - if enable { - value.set(f as u32); - } - }; - - // Samsung Exynos 9810 has a bug that big and little cores have different - // ISAs. And on older Android (pre-9), the kernel incorrectly reports - // that features available only on some cores are available on all cores. - // So, only check features that are known to be available on exynos-m3: - // $ rustc --print cfg --target aarch64-linux-android -C target-cpu=exynos-m3 | grep target_feature - // See also https://github.com/rust-lang/stdarch/pull/1378#discussion_r1103748342. - if is_exynos9810 { - enable_feature(Feature::fp, self.fp); - enable_feature(Feature::crc, self.crc32); - // ASIMD support requires float support - if half-floats are - // supported, it also requires half-float support: - let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp); - enable_feature(Feature::asimd, asimd); - // Cryptographic extensions require ASIMD - // AES also covers FEAT_PMULL - enable_feature(Feature::aes, self.aes && self.pmull && asimd); - enable_feature(Feature::sha2, self.sha1 && self.sha2 && asimd); - return value; - } - - enable_feature(Feature::fp, self.fp); - // Half-float support requires float support - enable_feature(Feature::fp16, self.fp && self.fphp); - // FHM (fp16fml in LLVM) requires half float support - enable_feature(Feature::fhm, self.fphp && self.fhm); - enable_feature(Feature::pmull, self.pmull); - enable_feature(Feature::crc, self.crc32); - enable_feature(Feature::lse, self.atomics); - enable_feature(Feature::lse2, self.uscat); - enable_feature(Feature::lse128, self.lse128 && self.atomics); - enable_feature(Feature::rcpc, self.lrcpc); - // RCPC2 (rcpc-immo in LLVM) requires RCPC support - let rcpc2 = self.ilrcpc && self.lrcpc; - enable_feature(Feature::rcpc2, rcpc2); - enable_feature(Feature::rcpc3, self.lrcpc3 && rcpc2); - enable_feature(Feature::dit, self.dit); - enable_feature(Feature::flagm, self.flagm); - enable_feature(Feature::flagm2, self.flagm2); - enable_feature(Feature::ssbs, self.ssbs); - enable_feature(Feature::sb, self.sb); - enable_feature(Feature::paca, self.paca); - enable_feature(Feature::pacg, self.pacg); - // enable_feature(Feature::pauth_lr, self.pauthlr); - enable_feature(Feature::dpb, self.dcpop); - enable_feature(Feature::dpb2, self.dcpodp); - enable_feature(Feature::rand, self.rng); - enable_feature(Feature::bti, self.bti); - enable_feature(Feature::mte, self.mte); - // jsconv requires float support - enable_feature(Feature::jsconv, self.jscvt && self.fp); - enable_feature(Feature::rdm, self.asimdrdm); - enable_feature(Feature::dotprod, self.asimddp); - enable_feature(Feature::frintts, self.frint); - - // FEAT_I8MM & FEAT_BF16 also include optional SVE components which linux exposes - // separately. We ignore that distinction here. - enable_feature(Feature::i8mm, self.i8mm); - enable_feature(Feature::bf16, self.bf16); - - // ASIMD support requires float support - if half-floats are - // supported, it also requires half-float support: - let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp); - enable_feature(Feature::asimd, asimd); - // ASIMD extensions require ASIMD support: - enable_feature(Feature::fcma, self.fcma && asimd); - enable_feature(Feature::sve, self.sve && asimd); - - // SVE extensions require SVE & ASIMD - enable_feature(Feature::f32mm, self.svef32mm && self.sve && asimd); - enable_feature(Feature::f64mm, self.svef64mm && self.sve && asimd); - - // Cryptographic extensions require ASIMD - enable_feature(Feature::aes, self.aes && asimd); - enable_feature(Feature::sha2, self.sha1 && self.sha2 && asimd); - // SHA512/SHA3 require SHA1 & SHA256 - enable_feature( - Feature::sha3, - self.sha512 && self.sha3 && self.sha1 && self.sha2 && asimd, - ); - enable_feature(Feature::sm4, self.sm3 && self.sm4 && asimd); - - // SVE2 requires SVE - let sve2 = self.sve2 && self.sve && asimd; - enable_feature(Feature::sve2, sve2); - enable_feature(Feature::sve2p1, self.sve2p1 && sve2); - // SVE2 extensions require SVE2 and crypto features - enable_feature( - Feature::sve2_aes, - self.sveaes && self.svepmull && sve2 && self.aes, - ); - enable_feature( - Feature::sve2_sm4, - self.svesm4 && sve2 && self.sm3 && self.sm4, - ); - enable_feature( - Feature::sve2_sha3, - self.svesha3 && sve2 && self.sha512 && self.sha3 && self.sha1 && self.sha2, - ); - enable_feature(Feature::sve2_bitperm, self.svebitperm && self.sve2); - enable_feature(Feature::sve_b16b16, self.bf16 && self.sveb16b16); - enable_feature(Feature::hbc, self.hbc); - enable_feature(Feature::mops, self.mops); - enable_feature(Feature::ecv, self.ecv); - enable_feature(Feature::lut, self.lut); - enable_feature(Feature::cssc, self.cssc); - enable_feature(Feature::fpmr, self.fpmr); - enable_feature(Feature::faminmax, self.faminmax); - let fp8 = self.f8cvt && self.faminmax && self.lut && self.bf16; - enable_feature(Feature::fp8, fp8); - let fp8fma = self.f8fma && fp8; - enable_feature(Feature::fp8fma, fp8fma); - let fp8dot4 = self.f8dp4 && fp8fma; - enable_feature(Feature::fp8dot4, fp8dot4); - enable_feature(Feature::fp8dot2, self.f8dp2 && fp8dot4); - enable_feature(Feature::wfxt, self.wfxt); - let sme = self.sme && self.bf16; - enable_feature(Feature::sme, sme); - enable_feature(Feature::sme_i16i64, self.smei16i64 && sme); - enable_feature(Feature::sme_f64f64, self.smef64f64 && sme); - enable_feature(Feature::sme_fa64, self.smefa64 && sme && sve2); - let sme2 = self.sme2 && sme; - enable_feature(Feature::sme2, sme2); - enable_feature(Feature::sme2p1, self.sme2p1 && sme2); - enable_feature( - Feature::sme_b16b16, - sme2 && self.bf16 && self.sveb16b16 && self.smeb16b16, - ); - enable_feature(Feature::sme_f16f16, self.smef16f16 && sme2); - enable_feature(Feature::sme_lutv2, self.smelutv2); - let sme_f8f32 = self.smef8f32 && sme2 && fp8; - enable_feature(Feature::sme_f8f32, sme_f8f32); - enable_feature(Feature::sme_f8f16, self.smef8f16 && sme_f8f32); - let ssve_fp8fma = self.smesf8fma && sme2 && fp8; - enable_feature(Feature::ssve_fp8fma, ssve_fp8fma); - let ssve_fp8dot4 = self.smesf8dp4 && ssve_fp8fma; - enable_feature(Feature::ssve_fp8dot4, ssve_fp8dot4); - enable_feature(Feature::ssve_fp8dot2, self.smesf8dp2 && ssve_fp8dot4); - } - value - } -} - -#[cfg(target_endian = "little")] -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(feature = "std_detect_file_io")] - mod auxv_from_file { - use super::auxvec::auxv_from_file; - use super::*; - // The baseline hwcaps used in the (artificial) auxv test files. - fn baseline_hwcaps() -> AtHwcap { - AtHwcap { - fp: true, - asimd: true, - aes: true, - pmull: true, - sha1: true, - sha2: true, - crc32: true, - atomics: true, - fphp: true, - asimdhp: true, - asimdrdm: true, - lrcpc: true, - dcpop: true, - asimddp: true, - ssbs: true, - ..AtHwcap::default() - } - } - - #[test] - fn linux_empty_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!( - AtHwcap::from(v), - AtHwcap { - // Some other HWCAP bits. - paca: true, - pacg: true, - // HWCAP2-only bits. - dcpodp: true, - frint: true, - rng: true, - bti: true, - mte: true, - ..baseline_hwcaps() - } - ); - } - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/arm.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/arm.rs deleted file mode 100644 index bbb173227d0..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/arm.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Run-time feature detection for ARM on Linux. - -use super::auxvec; -use crate::detect::{Feature, bit, cache}; - -/// Try to read the features from the auxiliary vector. -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let enable_feature = |value: &mut cache::Initializer, f, enable| { - if enable { - value.set(f as u32); - } - }; - - // The values are part of the platform-specific [asm/hwcap.h][hwcap] - // - // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h - if let Ok(auxv) = auxvec::auxv() { - enable_feature(&mut value, Feature::i8mm, bit::test(auxv.hwcap, 27)); - enable_feature(&mut value, Feature::dotprod, bit::test(auxv.hwcap, 24)); - enable_feature(&mut value, Feature::neon, bit::test(auxv.hwcap, 12)); - enable_feature(&mut value, Feature::pmull, bit::test(auxv.hwcap2, 1)); - enable_feature(&mut value, Feature::crc, bit::test(auxv.hwcap2, 4)); - enable_feature(&mut value, Feature::aes, bit::test(auxv.hwcap2, 0)); - // SHA2 requires SHA1 & SHA2 features - enable_feature( - &mut value, - Feature::sha2, - bit::test(auxv.hwcap2, 2) && bit::test(auxv.hwcap2, 3), - ); - return value; - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs deleted file mode 100644 index 54f52aa7533..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs +++ /dev/null @@ -1,341 +0,0 @@ -//! Parses ELF auxiliary vectors. -#![allow(dead_code)] - -pub(crate) const AT_NULL: usize = 0; - -/// Key to access the CPU Hardware capabilities bitfield. -pub(crate) const AT_HWCAP: usize = 16; -/// Key to access the CPU Hardware capabilities 2 bitfield. -#[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", -))] -pub(crate) const AT_HWCAP2: usize = 26; - -/// Cache HWCAP bitfields of the ELF Auxiliary Vector. -/// -/// If an entry cannot be read all the bits in the bitfield are set to zero. -/// This should be interpreted as all the features being disabled. -#[derive(Debug, Copy, Clone)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct AuxVec { - pub hwcap: usize, - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - pub hwcap2: usize, -} - -/// ELF Auxiliary Vector -/// -/// The auxiliary vector is a memory region in a running ELF program's stack -/// composed of (key: usize, value: usize) pairs. -/// -/// The keys used in the aux vector are platform dependent. For Linux, they are -/// defined in [linux/auxvec.h][auxvec_h]. The hardware capabilities of a given -/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. -/// -/// There is no perfect way of reading the auxiliary vector. -/// -/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use -/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation. -/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is -/// linked to the binary - if that is not the case the behavior is undefined. -/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will -/// try to read `/proc/self/auxv`. -/// - If that fails, this function returns an error. -/// -/// Note that run-time feature detection is not invoked for features that can -/// be detected at compile-time. -/// -/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on -/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` -/// is linked to the binary. -/// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) -/// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). -/// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) -/// use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) -/// - `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) -/// - `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) -/// have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). -/// -/// For more information about when `getauxval` is available check the great -/// [`auxv` crate documentation][auxv_docs]. -/// -/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h -/// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ -pub(crate) fn auxv() -> Result { - // Try to call a getauxval function. - if let Ok(hwcap) = getauxval(AT_HWCAP) { - // Targets with only AT_HWCAP: - #[cfg(any( - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "mips", - target_arch = "mips64", - target_arch = "loongarch32", - target_arch = "loongarch64", - ))] - { - // Zero could indicate that no features were detected, but it's also used to indicate - // an error. In either case, try the fallback. - if hwcap != 0 { - return Ok(AuxVec { hwcap }); - } - } - - // Targets with AT_HWCAP and AT_HWCAP2: - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - { - if let Ok(hwcap2) = getauxval(AT_HWCAP2) { - // Zero could indicate that no features were detected, but it's also used to indicate - // an error. In particular, on many platforms AT_HWCAP2 will be legitimately zero, - // since it contains the most recent feature flags. Use the fallback only if no - // features were detected at all. - if hwcap != 0 || hwcap2 != 0 { - return Ok(AuxVec { hwcap, hwcap2 }); - } - } - } - - // Intentionnaly not used - let _ = hwcap; - } - - #[cfg(feature = "std_detect_file_io")] - { - // If calling getauxval fails, try to read the auxiliary vector from - // its file: - auxv_from_file("/proc/self/auxv") - } - #[cfg(not(feature = "std_detect_file_io"))] - { - Err(()) - } -} - -/// Tries to read the `key` from the auxiliary vector by calling the -/// `getauxval` function. If the function is not linked, this function return `Err`. -fn getauxval(key: usize) -> Result { - type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong; - cfg_if::cfg_if! { - if #[cfg(all( - feature = "std_detect_dlsym_getauxval", - not(all( - target_os = "linux", - any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - not(target_os = "android"), - ))] { - let ffi_getauxval: F = unsafe { - let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); - if ptr.is_null() { - return Err(()); - } - core::mem::transmute(ptr) - }; - } else { - let ffi_getauxval: F = libc::getauxval; - } - } - Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize }) -} - -/// Tries to read the auxiliary vector from the `file`. If this fails, this -/// function returns `Err`. -#[cfg(feature = "std_detect_file_io")] -pub(super) fn auxv_from_file(file: &str) -> Result { - let file = super::read_file(file)?; - - // See . - // - // The auxiliary vector contains at most 34 (key,value) fields: from - // `AT_MINSIGSTKSZ` to `AT_NULL`, but its number may increase. - let len = file.len(); - let mut buf = alloc::vec![0_usize; 1 + len / core::mem::size_of::()]; - unsafe { - core::ptr::copy_nonoverlapping(file.as_ptr(), buf.as_mut_ptr() as *mut u8, len); - } - - auxv_from_buf(&buf) -} - -/// Tries to interpret the `buffer` as an auxiliary vector. If that fails, this -/// function returns `Err`. -#[cfg(feature = "std_detect_file_io")] -fn auxv_from_buf(buf: &[usize]) -> Result { - // Targets with only AT_HWCAP: - #[cfg(any( - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "mips", - target_arch = "mips64", - target_arch = "loongarch32", - target_arch = "loongarch64", - ))] - { - for el in buf.chunks(2) { - match el[0] { - AT_NULL => break, - AT_HWCAP => return Ok(AuxVec { hwcap: el[1] }), - _ => (), - } - } - } - // Targets with AT_HWCAP and AT_HWCAP2: - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - { - let mut hwcap = None; - // For some platforms, AT_HWCAP2 was added recently, so let it default to zero. - let mut hwcap2 = 0; - for el in buf.chunks(2) { - match el[0] { - AT_NULL => break, - AT_HWCAP => hwcap = Some(el[1]), - AT_HWCAP2 => hwcap2 = el[1], - _ => (), - } - } - - if let Some(hwcap) = hwcap { - return Ok(AuxVec { hwcap, hwcap2 }); - } - } - // Suppress unused variable - let _ = buf; - Err(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - // FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv - // does not always contain the AT_HWCAP key under qemu. - #[cfg(any( - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - #[test] - fn auxv_crate() { - let v = auxv(); - if let Ok(hwcap) = getauxval(AT_HWCAP) { - let rt_hwcap = v.expect("failed to find hwcap key").hwcap; - assert_eq!(rt_hwcap, hwcap); - } - - // Targets with AT_HWCAP and AT_HWCAP2: - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - { - if let Ok(hwcap2) = getauxval(AT_HWCAP2) { - let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2; - assert_eq!(rt_hwcap2, hwcap2); - } - } - } - - #[test] - fn auxv_dump() { - if let Ok(auxvec) = auxv() { - println!("{:?}", auxvec); - } else { - println!("both getauxval() and reading /proc/self/auxv failed!"); - } - } - - #[cfg(feature = "std_detect_file_io")] - cfg_if::cfg_if! { - if #[cfg(target_arch = "arm")] { - #[test] - fn linux_rpi3() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - assert_eq!(v.hwcap, 4174038); - assert_eq!(v.hwcap2, 16); - } - - #[test] - fn linux_macos_vb() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv"); - println!("file: {file}"); - // The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero. - let v = auxv_from_file(file).unwrap(); - assert_eq!(v.hwcap, 126614527); - assert_eq!(v.hwcap2, 0); - } - } else if #[cfg(target_arch = "aarch64")] { - #[cfg(target_endian = "little")] - #[test] - fn linux_artificial_aarch64() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - assert_eq!(v.hwcap, 0x0123456789abcdef); - assert_eq!(v.hwcap2, 0x02468ace13579bdf); - } - #[cfg(target_endian = "little")] - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - // An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP. - assert_ne!(v.hwcap, 0); - assert_eq!(v.hwcap2, 0); - } - } - } - - #[test] - #[cfg(feature = "std_detect_file_io")] - fn auxv_dump_procfs() { - if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { - println!("{:?}", auxvec); - } else { - println!("reading /proc/self/auxv failed!"); - } - } - - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - #[test] - #[cfg(feature = "std_detect_file_io")] - fn auxv_crate_procfs() { - if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { - assert_eq!(auxv().unwrap(), procfs_auxv); - } - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/loongarch.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/loongarch.rs deleted file mode 100644 index 14cc7a73183..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/loongarch.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Run-time feature detection for LoongArch on Linux. - -use super::auxvec; -use crate::detect::{Feature, bit, cache}; -use core::arch::asm; - -/// Try to read the features from the auxiliary vector. -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let enable_feature = |value: &mut cache::Initializer, feature, enable| { - if enable { - value.set(feature as u32); - } - }; - - // The values are part of the platform-specific [cpucfg] - // - // [cpucfg]: LoongArch Reference Manual Volume 1: Basic Architecture v1.1 - let cpucfg2: usize; - unsafe { - asm!( - "cpucfg {}, {}", - out(reg) cpucfg2, in(reg) 2, - options(pure, nomem, preserves_flags, nostack) - ); - } - let cpucfg3: usize; - unsafe { - asm!( - "cpucfg {}, {}", - out(reg) cpucfg3, in(reg) 3, - options(pure, nomem, preserves_flags, nostack) - ); - } - enable_feature(&mut value, Feature::frecipe, bit::test(cpucfg2, 25)); - enable_feature(&mut value, Feature::div32, bit::test(cpucfg2, 26)); - enable_feature(&mut value, Feature::lam_bh, bit::test(cpucfg2, 27)); - enable_feature(&mut value, Feature::lamcas, bit::test(cpucfg2, 28)); - enable_feature(&mut value, Feature::scq, bit::test(cpucfg2, 30)); - enable_feature(&mut value, Feature::ld_seq_sa, bit::test(cpucfg3, 23)); - - // The values are part of the platform-specific [asm/hwcap.h][hwcap] - // - // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h - if let Ok(auxv) = auxvec::auxv() { - enable_feature( - &mut value, - Feature::f, - bit::test(cpucfg2, 1) && bit::test(auxv.hwcap, 3), - ); - enable_feature( - &mut value, - Feature::d, - bit::test(cpucfg2, 2) && bit::test(auxv.hwcap, 3), - ); - enable_feature(&mut value, Feature::lsx, bit::test(auxv.hwcap, 4)); - enable_feature(&mut value, Feature::lasx, bit::test(auxv.hwcap, 5)); - enable_feature( - &mut value, - Feature::lbt, - bit::test(auxv.hwcap, 10) && bit::test(auxv.hwcap, 11) && bit::test(auxv.hwcap, 12), - ); - enable_feature(&mut value, Feature::lvz, bit::test(auxv.hwcap, 9)); - enable_feature(&mut value, Feature::ual, bit::test(auxv.hwcap, 2)); - return value; - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/mips.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/mips.rs deleted file mode 100644 index 0cfa8869887..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/mips.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Run-time feature detection for MIPS on Linux. - -use super::auxvec; -use crate::detect::{Feature, bit, cache}; - -/// Try to read the features from the auxiliary vector. -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let enable_feature = |value: &mut cache::Initializer, f, enable| { - if enable { - value.set(f as u32); - } - }; - - // The values are part of the platform-specific [asm/hwcap.h][hwcap] - // - // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/mips/include/uapi/asm/hwcap.h - if let Ok(auxv) = auxvec::auxv() { - enable_feature(&mut value, Feature::msa, bit::test(auxv.hwcap, 1)); - return value; - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs deleted file mode 100644 index 9accd41717b..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Run-time feature detection on Linux -//! -#[cfg(feature = "std_detect_file_io")] -use alloc::vec::Vec; - -mod auxvec; - -#[cfg(feature = "std_detect_file_io")] -fn read_file(path: &str) -> Result, ()> { - let mut path = Vec::from(path.as_bytes()); - path.push(0); - - unsafe { - let file = libc::open(path.as_ptr() as *const libc::c_char, libc::O_RDONLY); - if file == -1 { - return Err(()); - } - - let mut data = Vec::new(); - loop { - data.reserve(4096); - let spare = data.spare_capacity_mut(); - match libc::read(file, spare.as_mut_ptr() as *mut _, spare.len()) { - -1 => { - libc::close(file); - return Err(()); - } - 0 => break, - n => data.set_len(data.len() + n as usize), - } - } - - libc::close(file); - Ok(data) - } -} - -cfg_if::cfg_if! { - if #[cfg(target_arch = "aarch64")] { - mod aarch64; - pub(crate) use self::aarch64::detect_features; - } else if #[cfg(target_arch = "arm")] { - mod arm; - pub(crate) use self::arm::detect_features; - } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { - mod riscv; - pub(crate) use self::riscv::detect_features; - } else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] { - mod mips; - pub(crate) use self::mips::detect_features; - } else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] { - mod powerpc; - pub(crate) use self::powerpc::detect_features; - } else if #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] { - mod loongarch; - pub(crate) use self::loongarch::detect_features; - } else if #[cfg(target_arch = "s390x")] { - mod s390x; - pub(crate) use self::s390x::detect_features; - } else { - use crate::detect::cache; - /// Performs run-time feature detection. - pub(crate) fn detect_features() -> cache::Initializer { - cache::Initializer::default() - } - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/powerpc.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/powerpc.rs deleted file mode 100644 index 6a4f7e715d9..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/powerpc.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Run-time feature detection for PowerPC on Linux. - -use super::auxvec; -use crate::detect::{Feature, cache}; - -/// Try to read the features from the auxiliary vector. -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let enable_feature = |value: &mut cache::Initializer, f, enable| { - if enable { - value.set(f as u32); - } - }; - - // The values are part of the platform-specific [asm/cputable.h][cputable] - // - // [cputable]: https://github.com/torvalds/linux/blob/master/arch/powerpc/include/uapi/asm/cputable.h - if let Ok(auxv) = auxvec::auxv() { - // note: the PowerPC values are the mask to do the test (instead of the - // index of the bit to test like in ARM and Aarch64) - enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0); - enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0); - let power8_features = auxv.hwcap2 & 0x80000000 != 0; - enable_feature(&mut value, Feature::power8, power8_features); - enable_feature(&mut value, Feature::power8_altivec, power8_features); - enable_feature(&mut value, Feature::power8_crypto, power8_features); - enable_feature(&mut value, Feature::power8_vector, power8_features); - let power9_features = auxv.hwcap2 & 0x00800000 != 0; - enable_feature(&mut value, Feature::power9, power9_features); - enable_feature(&mut value, Feature::power9_altivec, power9_features); - enable_feature(&mut value, Feature::power9_vector, power9_features); - return value; - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/riscv.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/riscv.rs deleted file mode 100644 index db20538af95..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/riscv.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! Run-time feature detection for RISC-V on Linux. -//! -//! On RISC-V, detection using auxv only supports single-letter extensions. -//! So, we use riscv_hwprobe that supports multi-letter extensions if available. -//! - -use core::ptr; - -use super::super::riscv::imply_features; -use super::auxvec; -use crate::detect::{Feature, bit, cache}; - -// See -// for runtime status query constants. -const PR_RISCV_V_GET_CONTROL: libc::c_int = 70; -const PR_RISCV_V_VSTATE_CTRL_ON: libc::c_int = 2; -const PR_RISCV_V_VSTATE_CTRL_CUR_MASK: libc::c_int = 3; - -// See -// for riscv_hwprobe struct and hardware probing constants. - -#[repr(C)] -struct riscv_hwprobe { - key: i64, - value: u64, -} - -impl riscv_hwprobe { - // key is overwritten to -1 if not supported by riscv_hwprobe syscall. - pub fn get(&self) -> Option { - (self.key != -1).then_some(self.value) - } -} - -#[allow(non_upper_case_globals)] -const __NR_riscv_hwprobe: libc::c_long = 258; - -const RISCV_HWPROBE_KEY_BASE_BEHAVIOR: i64 = 3; -const RISCV_HWPROBE_BASE_BEHAVIOR_IMA: u64 = 1 << 0; - -const RISCV_HWPROBE_KEY_IMA_EXT_0: i64 = 4; -const RISCV_HWPROBE_IMA_FD: u64 = 1 << 0; -const RISCV_HWPROBE_IMA_C: u64 = 1 << 1; -const RISCV_HWPROBE_IMA_V: u64 = 1 << 2; -const RISCV_HWPROBE_EXT_ZBA: u64 = 1 << 3; -const RISCV_HWPROBE_EXT_ZBB: u64 = 1 << 4; -const RISCV_HWPROBE_EXT_ZBS: u64 = 1 << 5; -const RISCV_HWPROBE_EXT_ZICBOZ: u64 = 1 << 6; -const RISCV_HWPROBE_EXT_ZBC: u64 = 1 << 7; -const RISCV_HWPROBE_EXT_ZBKB: u64 = 1 << 8; -const RISCV_HWPROBE_EXT_ZBKC: u64 = 1 << 9; -const RISCV_HWPROBE_EXT_ZBKX: u64 = 1 << 10; -const RISCV_HWPROBE_EXT_ZKND: u64 = 1 << 11; -const RISCV_HWPROBE_EXT_ZKNE: u64 = 1 << 12; -const RISCV_HWPROBE_EXT_ZKNH: u64 = 1 << 13; -const RISCV_HWPROBE_EXT_ZKSED: u64 = 1 << 14; -const RISCV_HWPROBE_EXT_ZKSH: u64 = 1 << 15; -const RISCV_HWPROBE_EXT_ZKT: u64 = 1 << 16; -const RISCV_HWPROBE_EXT_ZVBB: u64 = 1 << 17; -const RISCV_HWPROBE_EXT_ZVBC: u64 = 1 << 18; -const RISCV_HWPROBE_EXT_ZVKB: u64 = 1 << 19; -const RISCV_HWPROBE_EXT_ZVKG: u64 = 1 << 20; -const RISCV_HWPROBE_EXT_ZVKNED: u64 = 1 << 21; -const RISCV_HWPROBE_EXT_ZVKNHA: u64 = 1 << 22; -const RISCV_HWPROBE_EXT_ZVKNHB: u64 = 1 << 23; -const RISCV_HWPROBE_EXT_ZVKSED: u64 = 1 << 24; -const RISCV_HWPROBE_EXT_ZVKSH: u64 = 1 << 25; -const RISCV_HWPROBE_EXT_ZVKT: u64 = 1 << 26; -const RISCV_HWPROBE_EXT_ZFH: u64 = 1 << 27; -const RISCV_HWPROBE_EXT_ZFHMIN: u64 = 1 << 28; -const RISCV_HWPROBE_EXT_ZIHINTNTL: u64 = 1 << 29; -const RISCV_HWPROBE_EXT_ZVFH: u64 = 1 << 30; -const RISCV_HWPROBE_EXT_ZVFHMIN: u64 = 1 << 31; -const RISCV_HWPROBE_EXT_ZFA: u64 = 1 << 32; -const RISCV_HWPROBE_EXT_ZTSO: u64 = 1 << 33; -const RISCV_HWPROBE_EXT_ZACAS: u64 = 1 << 34; -const RISCV_HWPROBE_EXT_ZICOND: u64 = 1 << 35; -const RISCV_HWPROBE_EXT_ZIHINTPAUSE: u64 = 1 << 36; -const RISCV_HWPROBE_EXT_ZVE32X: u64 = 1 << 37; -const RISCV_HWPROBE_EXT_ZVE32F: u64 = 1 << 38; -const RISCV_HWPROBE_EXT_ZVE64X: u64 = 1 << 39; -const RISCV_HWPROBE_EXT_ZVE64F: u64 = 1 << 40; -const RISCV_HWPROBE_EXT_ZVE64D: u64 = 1 << 41; -const RISCV_HWPROBE_EXT_ZIMOP: u64 = 1 << 42; -const RISCV_HWPROBE_EXT_ZCA: u64 = 1 << 43; -const RISCV_HWPROBE_EXT_ZCB: u64 = 1 << 44; -const RISCV_HWPROBE_EXT_ZCD: u64 = 1 << 45; -const RISCV_HWPROBE_EXT_ZCF: u64 = 1 << 46; -const RISCV_HWPROBE_EXT_ZCMOP: u64 = 1 << 47; -const RISCV_HWPROBE_EXT_ZAWRS: u64 = 1 << 48; -// Excluded because it only reports the existence of `prctl`-based pointer masking control. -// const RISCV_HWPROBE_EXT_SUPM: u64 = 1 << 49; -const RISCV_HWPROBE_EXT_ZICNTR: u64 = 1 << 50; -const RISCV_HWPROBE_EXT_ZIHPM: u64 = 1 << 51; -const RISCV_HWPROBE_EXT_ZFBFMIN: u64 = 1 << 52; -const RISCV_HWPROBE_EXT_ZVFBFMIN: u64 = 1 << 53; -const RISCV_HWPROBE_EXT_ZVFBFWMA: u64 = 1 << 54; -const RISCV_HWPROBE_EXT_ZICBOM: u64 = 1 << 55; -const RISCV_HWPROBE_EXT_ZAAMO: u64 = 1 << 56; -const RISCV_HWPROBE_EXT_ZALRSC: u64 = 1 << 57; - -const RISCV_HWPROBE_KEY_CPUPERF_0: i64 = 5; -const RISCV_HWPROBE_MISALIGNED_FAST: u64 = 3; -const RISCV_HWPROBE_MISALIGNED_MASK: u64 = 7; - -const RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF: i64 = 9; -const RISCV_HWPROBE_MISALIGNED_SCALAR_FAST: u64 = 3; - -const RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF: i64 = 10; -const RISCV_HWPROBE_MISALIGNED_VECTOR_FAST: u64 = 3; - -// syscall returns an unsupported error if riscv_hwprobe is not supported, -// so we can safely use this function on older versions of Linux. -fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool { - unsafe fn __riscv_hwprobe( - pairs: *mut riscv_hwprobe, - pair_count: libc::size_t, - cpu_set_size: libc::size_t, - cpus: *mut libc::c_ulong, - flags: libc::c_uint, - ) -> libc::c_long { - unsafe { - libc::syscall( - __NR_riscv_hwprobe, - pairs, - pair_count, - cpu_set_size, - cpus, - flags, - ) - } - } - - unsafe { __riscv_hwprobe(out.as_mut_ptr(), out.len(), 0, ptr::null_mut(), 0) == 0 } -} - -/// Read list of supported features from (1) the auxiliary vector -/// and (2) the results of `riscv_hwprobe` and `prctl` system calls. -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - let mut enable_feature = |feature, enable| { - if enable { - value.set(feature as u32); - } - }; - - // Use auxiliary vector to enable single-letter ISA extensions. - // The values are part of the platform-specific [asm/hwcap.h][hwcap] - // - // [hwcap]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/riscv/include/uapi/asm/hwcap.h?h=v6.15 - let auxv = auxvec::auxv().expect("read auxvec"); // should not fail on RISC-V platform - let mut has_i = bit::test(auxv.hwcap, (b'i' - b'a').into()); - #[allow(clippy::eq_op)] - enable_feature(Feature::a, bit::test(auxv.hwcap, (b'a' - b'a').into())); - enable_feature(Feature::c, bit::test(auxv.hwcap, (b'c' - b'a').into())); - enable_feature(Feature::d, bit::test(auxv.hwcap, (b'd' - b'a').into())); - enable_feature(Feature::f, bit::test(auxv.hwcap, (b'f' - b'a').into())); - enable_feature(Feature::m, bit::test(auxv.hwcap, (b'm' - b'a').into())); - let has_v = bit::test(auxv.hwcap, (b'v' - b'a').into()); - let mut is_v_set = false; - - // Use riscv_hwprobe syscall to query more extensions and - // performance-related capabilities. - 'hwprobe: { - macro_rules! init { - { $($name: ident : $key: expr),* $(,)? } => { - #[repr(usize)] - enum Indices { $($name),* } - let mut t = [$(riscv_hwprobe { key: $key, value: 0 }),*]; - macro_rules! data_mut { () => { &mut t } } - macro_rules! query { [$idx: ident] => { t[Indices::$idx as usize].get() } } - } - } - init! { - BaseBehavior: RISCV_HWPROBE_KEY_BASE_BEHAVIOR, - Extensions: RISCV_HWPROBE_KEY_IMA_EXT_0, - MisalignedScalarPerf: RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF, - MisalignedVectorPerf: RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, - MisalignedScalarPerfFallback: RISCV_HWPROBE_KEY_CPUPERF_0, - }; - if !_riscv_hwprobe(data_mut!()) { - break 'hwprobe; - } - - // Query scalar misaligned behavior. - if let Some(value) = query![MisalignedScalarPerf] { - enable_feature( - Feature::unaligned_scalar_mem, - value == RISCV_HWPROBE_MISALIGNED_SCALAR_FAST, - ); - } else if let Some(value) = query![MisalignedScalarPerfFallback] { - // Deprecated method for fallback - enable_feature( - Feature::unaligned_scalar_mem, - value & RISCV_HWPROBE_MISALIGNED_MASK == RISCV_HWPROBE_MISALIGNED_FAST, - ); - } - - // Query vector misaligned behavior. - if let Some(value) = query![MisalignedVectorPerf] { - enable_feature( - Feature::unaligned_vector_mem, - value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST, - ); - } - - // Query whether "I" base and extensions "M" and "A" (as in the ISA - // manual version 2.2) are enabled. "I" base at that time corresponds - // to "I", "Zicsr", "Zicntr" and "Zifencei" (as in the ISA manual version - // 20240411). - // This is a current requirement of - // `RISCV_HWPROBE_KEY_IMA_EXT_0`-based tests. - if query![BaseBehavior].is_none_or(|value| value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA == 0) { - break 'hwprobe; - } - has_i = true; - enable_feature(Feature::zicsr, true); - enable_feature(Feature::zicntr, true); - enable_feature(Feature::zifencei, true); - enable_feature(Feature::m, true); - enable_feature(Feature::a, true); - - // Enable features based on `RISCV_HWPROBE_KEY_IMA_EXT_0`. - let Some(ima_ext_0) = query![Extensions] else { - break 'hwprobe; - }; - let test = |mask| (ima_ext_0 & mask) != 0; - - enable_feature(Feature::d, test(RISCV_HWPROBE_IMA_FD)); // F is implied. - enable_feature(Feature::c, test(RISCV_HWPROBE_IMA_C)); - - enable_feature(Feature::zicntr, test(RISCV_HWPROBE_EXT_ZICNTR)); - enable_feature(Feature::zihpm, test(RISCV_HWPROBE_EXT_ZIHPM)); - - enable_feature(Feature::zihintntl, test(RISCV_HWPROBE_EXT_ZIHINTNTL)); - enable_feature(Feature::zihintpause, test(RISCV_HWPROBE_EXT_ZIHINTPAUSE)); - enable_feature(Feature::zimop, test(RISCV_HWPROBE_EXT_ZIMOP)); - enable_feature(Feature::zicbom, test(RISCV_HWPROBE_EXT_ZICBOM)); - enable_feature(Feature::zicboz, test(RISCV_HWPROBE_EXT_ZICBOZ)); - enable_feature(Feature::zicond, test(RISCV_HWPROBE_EXT_ZICOND)); - - enable_feature(Feature::zalrsc, test(RISCV_HWPROBE_EXT_ZALRSC)); - enable_feature(Feature::zaamo, test(RISCV_HWPROBE_EXT_ZAAMO)); - enable_feature(Feature::zawrs, test(RISCV_HWPROBE_EXT_ZAWRS)); - enable_feature(Feature::zacas, test(RISCV_HWPROBE_EXT_ZACAS)); - enable_feature(Feature::ztso, test(RISCV_HWPROBE_EXT_ZTSO)); - - enable_feature(Feature::zba, test(RISCV_HWPROBE_EXT_ZBA)); - enable_feature(Feature::zbb, test(RISCV_HWPROBE_EXT_ZBB)); - enable_feature(Feature::zbs, test(RISCV_HWPROBE_EXT_ZBS)); - enable_feature(Feature::zbc, test(RISCV_HWPROBE_EXT_ZBC)); - - enable_feature(Feature::zbkb, test(RISCV_HWPROBE_EXT_ZBKB)); - enable_feature(Feature::zbkc, test(RISCV_HWPROBE_EXT_ZBKC)); - enable_feature(Feature::zbkx, test(RISCV_HWPROBE_EXT_ZBKX)); - enable_feature(Feature::zknd, test(RISCV_HWPROBE_EXT_ZKND)); - enable_feature(Feature::zkne, test(RISCV_HWPROBE_EXT_ZKNE)); - enable_feature(Feature::zknh, test(RISCV_HWPROBE_EXT_ZKNH)); - enable_feature(Feature::zksed, test(RISCV_HWPROBE_EXT_ZKSED)); - enable_feature(Feature::zksh, test(RISCV_HWPROBE_EXT_ZKSH)); - enable_feature(Feature::zkt, test(RISCV_HWPROBE_EXT_ZKT)); - - enable_feature(Feature::zcmop, test(RISCV_HWPROBE_EXT_ZCMOP)); - enable_feature(Feature::zca, test(RISCV_HWPROBE_EXT_ZCA)); - enable_feature(Feature::zcf, test(RISCV_HWPROBE_EXT_ZCF)); - enable_feature(Feature::zcd, test(RISCV_HWPROBE_EXT_ZCD)); - enable_feature(Feature::zcb, test(RISCV_HWPROBE_EXT_ZCB)); - - enable_feature(Feature::zfh, test(RISCV_HWPROBE_EXT_ZFH)); - enable_feature(Feature::zfhmin, test(RISCV_HWPROBE_EXT_ZFHMIN)); - enable_feature(Feature::zfa, test(RISCV_HWPROBE_EXT_ZFA)); - enable_feature(Feature::zfbfmin, test(RISCV_HWPROBE_EXT_ZFBFMIN)); - - // Use prctl (if any) to determine whether the vector extension - // is enabled on the current thread (assuming the entire process - // share the same status). If prctl fails (e.g. QEMU userland emulator - // as of version 9.2.3), use auxiliary vector to retrieve the default - // vector status on the process startup. - let has_vectors = { - let v_status = unsafe { libc::prctl(PR_RISCV_V_GET_CONTROL) }; - if v_status >= 0 { - (v_status & PR_RISCV_V_VSTATE_CTRL_CUR_MASK) == PR_RISCV_V_VSTATE_CTRL_ON - } else { - has_v - } - }; - if has_vectors { - enable_feature(Feature::v, test(RISCV_HWPROBE_IMA_V)); - enable_feature(Feature::zve32x, test(RISCV_HWPROBE_EXT_ZVE32X)); - enable_feature(Feature::zve32f, test(RISCV_HWPROBE_EXT_ZVE32F)); - enable_feature(Feature::zve64x, test(RISCV_HWPROBE_EXT_ZVE64X)); - enable_feature(Feature::zve64f, test(RISCV_HWPROBE_EXT_ZVE64F)); - enable_feature(Feature::zve64d, test(RISCV_HWPROBE_EXT_ZVE64D)); - - enable_feature(Feature::zvbb, test(RISCV_HWPROBE_EXT_ZVBB)); - enable_feature(Feature::zvbc, test(RISCV_HWPROBE_EXT_ZVBC)); - enable_feature(Feature::zvkb, test(RISCV_HWPROBE_EXT_ZVKB)); - enable_feature(Feature::zvkg, test(RISCV_HWPROBE_EXT_ZVKG)); - enable_feature(Feature::zvkned, test(RISCV_HWPROBE_EXT_ZVKNED)); - enable_feature(Feature::zvknha, test(RISCV_HWPROBE_EXT_ZVKNHA)); - enable_feature(Feature::zvknhb, test(RISCV_HWPROBE_EXT_ZVKNHB)); - enable_feature(Feature::zvksed, test(RISCV_HWPROBE_EXT_ZVKSED)); - enable_feature(Feature::zvksh, test(RISCV_HWPROBE_EXT_ZVKSH)); - enable_feature(Feature::zvkt, test(RISCV_HWPROBE_EXT_ZVKT)); - - enable_feature(Feature::zvfh, test(RISCV_HWPROBE_EXT_ZVFH)); - enable_feature(Feature::zvfhmin, test(RISCV_HWPROBE_EXT_ZVFHMIN)); - enable_feature(Feature::zvfbfmin, test(RISCV_HWPROBE_EXT_ZVFBFMIN)); - enable_feature(Feature::zvfbfwma, test(RISCV_HWPROBE_EXT_ZVFBFWMA)); - } - is_v_set = true; - }; - - // Set V purely depending on the auxiliary vector - // only if no fine-grained vector extension detection is available. - if !is_v_set { - enable_feature(Feature::v, has_v); - } - - // Handle base ISA. - // If future RV128I is supported, implement with `enable_feature` here. - // Note that we should use `target_arch` instead of `target_pointer_width` - // to avoid misdetection caused by experimental ABIs such as RV64ILP32. - #[cfg(target_arch = "riscv64")] - enable_feature(Feature::rv64i, has_i); - #[cfg(target_arch = "riscv32")] - enable_feature(Feature::rv32i, has_i); - - imply_features(value) -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs deleted file mode 100644 index 9b53f526d61..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/linux/s390x.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Run-time feature detection for s390x on Linux. - -use super::auxvec; -use crate::detect::{Feature, bit, cache}; - -/// Try to read the features from the auxiliary vector -pub(crate) fn detect_features() -> cache::Initializer { - let opt_hwcap: Option = auxvec::auxv().ok().map(Into::into); - let facilities = ExtendedFacilityList::new(); - cache(opt_hwcap, facilities) -} - -#[derive(Debug, Default, PartialEq)] -struct AtHwcap { - esan3: bool, - zarch: bool, - stfle: bool, - msa: bool, - ldisp: bool, - eimm: bool, - dfp: bool, - hpage: bool, - etf3eh: bool, - high_gprs: bool, - te: bool, - vxrs: bool, - vxrs_bcd: bool, - vxrs_ext: bool, - gs: bool, - vxrs_ext2: bool, - vxrs_pde: bool, - sort: bool, - dflt: bool, - vxrs_pde2: bool, - nnpa: bool, - pci_mio: bool, - sie: bool, -} - -impl From for AtHwcap { - /// Reads AtHwcap from the auxiliary vector. - fn from(auxv: auxvec::AuxVec) -> Self { - AtHwcap { - esan3: bit::test(auxv.hwcap, 0), - zarch: bit::test(auxv.hwcap, 1), - stfle: bit::test(auxv.hwcap, 2), - msa: bit::test(auxv.hwcap, 3), - ldisp: bit::test(auxv.hwcap, 4), - eimm: bit::test(auxv.hwcap, 5), - dfp: bit::test(auxv.hwcap, 6), - hpage: bit::test(auxv.hwcap, 7), - etf3eh: bit::test(auxv.hwcap, 8), - high_gprs: bit::test(auxv.hwcap, 9), - te: bit::test(auxv.hwcap, 10), - vxrs: bit::test(auxv.hwcap, 11), - vxrs_bcd: bit::test(auxv.hwcap, 12), - vxrs_ext: bit::test(auxv.hwcap, 13), - gs: bit::test(auxv.hwcap, 14), - vxrs_ext2: bit::test(auxv.hwcap, 15), - vxrs_pde: bit::test(auxv.hwcap, 16), - sort: bit::test(auxv.hwcap, 17), - dflt: bit::test(auxv.hwcap, 18), - vxrs_pde2: bit::test(auxv.hwcap, 19), - nnpa: bit::test(auxv.hwcap, 20), - pci_mio: bit::test(auxv.hwcap, 21), - sie: bit::test(auxv.hwcap, 22), - } - } -} - -struct ExtendedFacilityList([u64; 4]); - -impl ExtendedFacilityList { - fn new() -> Self { - let mut result: [u64; 4] = [0; 4]; - // SAFETY: rust/llvm only support s390x version with the `stfle` instruction. - unsafe { - core::arch::asm!( - // equivalently ".insn s, 0xb2b00000, 0({1})", - "stfle 0({})", - in(reg_addr) result.as_mut_ptr() , - inout("r0") result.len() as u64 - 1 => _, - options(nostack) - ); - } - Self(result) - } - - const fn get_bit(&self, n: usize) -> bool { - // NOTE: bits are numbered from the left. - self.0[n / 64] & (1 << (63 - (n % 64))) != 0 - } -} - -/// Initializes the cache from the feature bits. -/// -/// These values are part of the platform-specific [asm/elf.h][kernel], and are a selection of the -/// fields found in the [Facility Indications]. -/// -/// [Facility Indications]: https://www.ibm.com/support/pages/sites/default/files/2021-05/SA22-7871-10.pdf#page=63 -/// [kernel]: https://github.com/torvalds/linux/blob/b62cef9a5c673f1b8083159f5dc03c1c5daced2f/arch/s390/include/asm/elf.h#L129 -fn cache(hwcap: Option, facilities: ExtendedFacilityList) -> cache::Initializer { - let mut value = cache::Initializer::default(); - - { - let mut enable_if_set = |bit_index, f| { - if facilities.get_bit(bit_index) { - value.set(f as u32); - } - }; - - // We use HWCAP for `vector` because it requires both hardware and kernel support. - if let Some(AtHwcap { vxrs: true, .. }) = hwcap { - // vector and related - - enable_if_set(129, Feature::vector); - - enable_if_set(135, Feature::vector_enhancements_1); - enable_if_set(148, Feature::vector_enhancements_2); - enable_if_set(198, Feature::vector_enhancements_3); - - enable_if_set(134, Feature::vector_packed_decimal); - enable_if_set(152, Feature::vector_packed_decimal_enhancement); - enable_if_set(192, Feature::vector_packed_decimal_enhancement_2); - enable_if_set(199, Feature::vector_packed_decimal_enhancement_3); - - enable_if_set(165, Feature::nnp_assist); - } - - // others - - enable_if_set(76, Feature::message_security_assist_extension3); - enable_if_set(77, Feature::message_security_assist_extension4); - enable_if_set(57, Feature::message_security_assist_extension5); - enable_if_set(146, Feature::message_security_assist_extension8); - enable_if_set(155, Feature::message_security_assist_extension9); - enable_if_set(86, Feature::message_security_assist_extension12); - - enable_if_set(58, Feature::miscellaneous_extensions_2); - enable_if_set(61, Feature::miscellaneous_extensions_3); - enable_if_set(84, Feature::miscellaneous_extensions_4); - - enable_if_set(45, Feature::high_word); - enable_if_set(73, Feature::transactional_execution); - enable_if_set(133, Feature::guarded_storage); - enable_if_set(150, Feature::enhanced_sort); - enable_if_set(151, Feature::deflate_conversion); - enable_if_set(201, Feature::concurrent_functions); - } - - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs deleted file mode 100644 index cfe4ad10ad6..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/openbsd/aarch64.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Run-time feature detection for Aarch64 on OpenBSD. -//! -//! OpenBSD doesn't trap the mrs instruction, but exposes the system registers through sysctl. -//! https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8 -//! https://github.com/golang/go/commit/cd54ef1f61945459486e9eea2f016d99ef1da925 - -use crate::detect::cache; -use core::{mem::MaybeUninit, ptr}; - -// Defined in machine/cpu.h. -// https://github.com/openbsd/src/blob/72ccc03bd11da614f31f7ff76e3f6fce99bc1c79/sys/arch/arm64/include/cpu.h#L25-L40 -const CPU_ID_AA64ISAR0: libc::c_int = 2; -const CPU_ID_AA64ISAR1: libc::c_int = 3; -const CPU_ID_AA64MMFR2: libc::c_int = 7; -const CPU_ID_AA64PFR0: libc::c_int = 8; - -/// Try to read the features from the system registers. -pub(crate) fn detect_features() -> cache::Initializer { - // ID_AA64ISAR0_EL1 and ID_AA64ISAR1_EL1 are supported on OpenBSD 7.1+. - // https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8 - // Others are supported on OpenBSD 7.3+. - // https://github.com/openbsd/src/commit/c7654cd65262d532212f65123ee3905ba200365c - // sysctl returns an unsupported error if operation is not supported, - // so we can safely use this function on older versions of OpenBSD. - let aa64isar0 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64ISAR0]).unwrap_or(0); - let aa64isar1 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64ISAR1]).unwrap_or(0); - let aa64mmfr2 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64MMFR2]).unwrap_or(0); - // Do not use unwrap_or(0) because in fp and asimd fields, 0 indicates that - // the feature is available. - let aa64pfr0 = sysctl64(&[libc::CTL_MACHDEP, CPU_ID_AA64PFR0]); - - super::aarch64::parse_system_registers(aa64isar0, aa64isar1, aa64mmfr2, aa64pfr0) -} - -#[inline] -fn sysctl64(mib: &[libc::c_int]) -> Option { - const OUT_LEN: libc::size_t = core::mem::size_of::(); - let mut out = MaybeUninit::::uninit(); - let mut out_len = OUT_LEN; - let res = unsafe { - libc::sysctl( - mib.as_ptr(), - mib.len() as libc::c_uint, - out.as_mut_ptr() as *mut libc::c_void, - &mut out_len, - ptr::null_mut(), - 0, - ) - }; - if res == -1 || out_len != OUT_LEN { - return None; - } - // SAFETY: we've checked that sysctl was successful and `out` was filled. - Some(unsafe { out.assume_init() }) -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/other.rs b/library/stdarch/crates/std_detect/src/detect/os/other.rs deleted file mode 100644 index 091fafc4ebf..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/other.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Other operating systems - -use crate::detect::cache; - -#[allow(dead_code)] -pub(crate) fn detect_features() -> cache::Initializer { - cache::Initializer::default() -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/riscv.rs b/library/stdarch/crates/std_detect/src/detect/os/riscv.rs deleted file mode 100644 index 4c59ede8029..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/riscv.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Run-time feature detection utility for RISC-V. -//! -//! On RISC-V, full feature detection needs a help of one or more -//! feature detection mechanisms (usually provided by the operating system). -//! -//! RISC-V architecture defines many extensions and some have dependency to others. -//! More importantly, some of them cannot be enabled without resolving such -//! dependencies due to limited set of features that such mechanisms provide. -//! -//! This module provides an OS-independent utility to process such relations -//! between RISC-V extensions. - -use crate::detect::{Feature, cache}; - -/// Imply features by the given set of enabled features. -/// -/// Note that it does not perform any consistency checks including existence of -/// conflicting extensions and/or complicated requirements. Eliminating such -/// inconsistencies is the responsibility of the feature detection logic and -/// its provider(s). -pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initializer { - loop { - // Check convergence of the feature flags later. - let prev = value; - - // Expect that the optimizer turns repeated operations into - // a fewer number of bit-manipulation operations. - macro_rules! imply { - // Regular implication: - // A1 => (B1[, B2...]), A2 => (B1[, B2...]) and so on. - ($($from: ident)|+ => $($to: ident)&+) => { - if [$(Feature::$from as u32),+].iter().any(|&x| value.test(x)) { - $( - value.set(Feature::$to as u32); - )+ - } - }; - // Implication with multiple requirements: - // A1 && A2 ... => (B1[, B2...]). - ($($from: ident)&+ => $($to: ident)&+) => { - if [$(Feature::$from as u32),+].iter().all(|&x| value.test(x)) { - $( - value.set(Feature::$to as u32); - )+ - } - }; - } - macro_rules! group { - ($group: ident == $($member: ident)&+) => { - // Forward implication as defined in the specifications. - imply!($group => $($member)&+); - // Reverse implication to "group extension" from its members. - // This is not a part of specifications but convenient for - // feature detection and implemented in e.g. LLVM. - imply!($($member)&+ => $group); - }; - } - - /* - If a dependency/implication is not explicitly stated in the - specification, it is denoted as a comment as follows: - "defined as subset": - The latter extension is described as a subset of the former - (but the evidence is weak). - "functional": - The former extension is functionally a superset of the latter - (no direct references though). - */ - - imply!(zvbb => zvkb); - - // Certain set of vector cryptography extensions form a group. - group!(zvkn == zvkned & zvknhb & zvkb & zvkt); - group!(zvknc == zvkn & zvbc); - group!(zvkng == zvkn & zvkg); - group!(zvks == zvksed & zvksh & zvkb & zvkt); - group!(zvksc == zvks & zvbc); - group!(zvksg == zvks & zvkg); - - imply!(zvknhb => zvknha); // functional - - // For vector cryptography, Zvknhb and Zvbc require integer arithmetic - // with EEW=64 (Zve64x) while others not depending on them - // require EEW=32 (Zve32x). - imply!(zvknhb | zvbc => zve64x); - imply!(zvbb | zvkb | zvkg | zvkned | zvknha | zvksed | zvksh => zve32x); - - imply!(zbc => zbkc); // defined as subset - group!(zkn == zbkb & zbkc & zbkx & zkne & zknd & zknh); - group!(zks == zbkb & zbkc & zbkx & zksed & zksh); - group!(zk == zkn & zkr & zkt); - - imply!(zacas => zaamo); - group!(a == zalrsc & zaamo); - - group!(b == zba & zbb & zbs); - - imply!(zcf => zca & f); - imply!(zcd => zca & d); - imply!(zcmop | zcb => zca); - - imply!(zhinx => zhinxmin); - imply!(zdinx | zhinxmin => zfinx); - - imply!(zvfh => zvfhmin); // functional - imply!(zvfh => zve32f & zfhmin); - imply!(zvfhmin => zve32f); - imply!(zvfbfwma => zvfbfmin & zfbfmin); - imply!(zvfbfmin => zve32f); - - imply!(v => zve64d); - imply!(zve64d => zve64f & d); - imply!(zve64f => zve64x & zve32f); - imply!(zve64x => zve32x); - imply!(zve32f => zve32x & f); - - imply!(zfh => zfhmin); - imply!(q => d); - imply!(d | zfhmin | zfa => f); - imply!(zfbfmin => f); // and some of (not all) "Zfh" instructions. - - // Relatively complex implication rules from the "C" extension. - imply!(c => zca); - imply!(c & d => zcd); - #[cfg(target_arch = "riscv32")] - imply!(c & f => zcf); - - imply!(zicntr | zihpm | f | zfinx | zve32x => zicsr); - - // Loop until the feature flags converge. - if prev == value { - return value; - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn simple_direct() { - let mut value = cache::Initializer::default(); - value.set(Feature::f as u32); - // F (and other extensions with CSRs) -> Zicsr - assert!(imply_features(value).test(Feature::zicsr as u32)); - } - - #[test] - fn simple_indirect() { - let mut value = cache::Initializer::default(); - value.set(Feature::q as u32); - // Q -> D, D -> F, F -> Zicsr - assert!(imply_features(value).test(Feature::zicsr as u32)); - } - - #[test] - fn complex_zcd() { - let mut value = cache::Initializer::default(); - // C & D -> Zcd - value.set(Feature::c as u32); - assert!(!imply_features(value).test(Feature::zcd as u32)); - value.set(Feature::d as u32); - assert!(imply_features(value).test(Feature::zcd as u32)); - } - - #[test] - fn group_simple_forward() { - let mut value = cache::Initializer::default(); - // A -> Zalrsc & Zaamo (forward implication) - value.set(Feature::a as u32); - let value = imply_features(value); - assert!(value.test(Feature::zalrsc as u32)); - assert!(value.test(Feature::zaamo as u32)); - } - - #[test] - fn group_simple_backward() { - let mut value = cache::Initializer::default(); - // Zalrsc & Zaamo -> A (reverse implication) - value.set(Feature::zalrsc as u32); - value.set(Feature::zaamo as u32); - assert!(imply_features(value).test(Feature::a as u32)); - } - - #[test] - fn group_complex_convergence() { - let mut value = cache::Initializer::default(); - // Needs 3 iterations to converge - // (and 4th iteration for convergence checking): - // 1. [Zvksc] -> Zvks & Zvbc - // 2. Zvks -> Zvksed & Zvksh & Zvkb & Zvkt - // 3a. [Zvkned] & [Zvknhb] & [Zvkb] & Zvkt -> {Zvkn} - // 3b. Zvkn & Zvbc -> {Zvknc} - value.set(Feature::zvksc as u32); - value.set(Feature::zvkned as u32); - value.set(Feature::zvknhb as u32); - value.set(Feature::zvkb as u32); - let value = imply_features(value); - assert!(value.test(Feature::zvkn as u32)); - assert!(value.test(Feature::zvknc as u32)); - } -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/windows/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/windows/aarch64.rs deleted file mode 100644 index 937f9f26eed..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/windows/aarch64.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! Run-time feature detection for Aarch64 on Windows. - -use crate::detect::{Feature, cache}; - -/// Try to read the features using IsProcessorFeaturePresent. -pub(crate) fn detect_features() -> cache::Initializer { - type DWORD = u32; - type BOOL = i32; - - const FALSE: BOOL = 0; - // The following Microsoft documents isn't updated for aarch64. - // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent - // These are defined in winnt.h of Windows SDK - const PF_ARM_VFP_32_REGISTERS_AVAILABLE: u32 = 18; - const PF_ARM_NEON_INSTRUCTIONS_AVAILABLE: u32 = 19; - const PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE: u32 = 30; - const PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE: u32 = 31; - const PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE: u32 = 34; - const PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE: u32 = 43; - const PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE: u32 = 44; - const PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE: u32 = 45; - const PF_ARM_SVE_INSTRUCTIONS_AVAILABLE: u32 = 46; - const PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE: u32 = 47; - const PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE: u32 = 48; - const PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE: u32 = 49; - const PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE: u32 = 50; - const PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE: u32 = 51; - // const PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE: u32 = 52; - // const PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE: u32 = 53; - const PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE: u32 = 54; - const PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 55; - const PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE: u32 = 56; - // const PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE: u32 = 57; - // const PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE: u32 = 58; - // const PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE: u32 = 59; - - unsafe extern "system" { - fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL; - } - - let mut value = cache::Initializer::default(); - { - let mut enable_feature = |f, enable| { - if enable { - value.set(f as u32); - } - }; - - // Some features may be supported on current CPU, - // but no way to detect it by OS API. - // Also, we require unsafe block for the extern "system" calls. - unsafe { - enable_feature( - Feature::fp, - IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::asimd, - IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::crc, - IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::lse, - IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::dotprod, - IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::jsconv, - IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::rcpc, - IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve, - IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve2, - IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve2p1, - IsProcessorFeaturePresent(PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve2_aes, - IsProcessorFeaturePresent(PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE) != FALSE - && IsProcessorFeaturePresent(PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE) - != FALSE, - ); - enable_feature( - Feature::sve2_bitperm, - IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve_b16b16, - IsProcessorFeaturePresent(PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve2_sha3, - IsProcessorFeaturePresent(PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - enable_feature( - Feature::sve2_sm4, - IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE) != FALSE, - ); - // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE means aes, sha1, sha2 and - // pmull support - let crypto = - IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != FALSE; - enable_feature(Feature::aes, crypto); - enable_feature(Feature::pmull, crypto); - enable_feature(Feature::sha2, crypto); - } - } - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/os/x86.rs b/library/stdarch/crates/std_detect/src/detect/os/x86.rs deleted file mode 100644 index 8565c2f85e2..00000000000 --- a/library/stdarch/crates/std_detect/src/detect/os/x86.rs +++ /dev/null @@ -1,335 +0,0 @@ -//! x86 run-time feature detection is OS independent. - -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -use core::mem; - -use crate::detect::{Feature, bit, cache}; - -/// Run-time feature detection on x86 works by using the CPUID instruction. -/// -/// The [CPUID Wikipedia page][wiki_cpuid] contains -/// all the information about which flags to set to query which values, and in -/// which registers these are reported. -/// -/// The definitive references are: -/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2: -/// Instruction Set Reference, A-Z][intel64_ref]. -/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and -/// System Instructions][amd64_ref]. -/// -/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID -/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf -/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf -#[allow(clippy::similar_names)] -pub(crate) fn detect_features() -> cache::Initializer { - let mut value = cache::Initializer::default(); - - if cfg!(target_env = "sgx") { - // doesn't support this because it is untrusted data - return value; - } - - // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU - // has `cpuid` support. - - // 0. EAX = 0: Basic Information: - // - EAX returns the "Highest Function Parameter", that is, the maximum - // leaf value for subsequent calls of `cpuinfo` in range [0, - // 0x8000_0000]. - The vendor ID is stored in 12 u8 ascii chars, - // returned in EBX, EDX, and ECX (in that order): - let (max_basic_leaf, vendor_id) = unsafe { - let CpuidResult { - eax: max_basic_leaf, - ebx, - ecx, - edx, - } = __cpuid(0); - let vendor_id: [[u8; 4]; 3] = [ebx.to_ne_bytes(), edx.to_ne_bytes(), ecx.to_ne_bytes()]; - let vendor_id: [u8; 12] = mem::transmute(vendor_id); - (max_basic_leaf, vendor_id) - }; - - if max_basic_leaf < 1 { - // Earlier Intel 486, CPUID not implemented - return value; - } - - // EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits"; - // Contains information about most x86 features. - let CpuidResult { - ecx: proc_info_ecx, - edx: proc_info_edx, - .. - } = unsafe { __cpuid(0x0000_0001_u32) }; - - // EAX = 7: Queries "Extended Features"; - // Contains information about bmi,bmi2, and avx2 support. - let ( - extended_features_ebx, - extended_features_ecx, - extended_features_edx, - extended_features_eax_leaf_1, - extended_features_edx_leaf_1, - ) = if max_basic_leaf >= 7 { - let CpuidResult { ebx, ecx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; - let CpuidResult { - eax: eax_1, - edx: edx_1, - .. - } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; - (ebx, ecx, edx, eax_1, edx_1) - } else { - (0, 0, 0, 0, 0) // CPUID does not support "Extended Features" - }; - - // EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported - // - EAX returns the max leaf value for extended information, that is, - // `cpuid` calls in range [0x8000_0000; u32::MAX]: - let CpuidResult { - eax: extended_max_basic_leaf, - .. - } = unsafe { __cpuid(0x8000_0000_u32) }; - - // EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature - // Bits" - let extended_proc_info_ecx = if extended_max_basic_leaf >= 1 { - let CpuidResult { ecx, .. } = unsafe { __cpuid(0x8000_0001_u32) }; - ecx - } else { - 0 - }; - - { - // borrows value till the end of this scope: - let mut enable = |r, rb, f| { - let present = bit::test(r as usize, rb); - if present { - value.set(f as u32); - } - present - }; - - enable(proc_info_ecx, 0, Feature::sse3); - enable(proc_info_ecx, 1, Feature::pclmulqdq); - enable(proc_info_ecx, 9, Feature::ssse3); - enable(proc_info_ecx, 13, Feature::cmpxchg16b); - enable(proc_info_ecx, 19, Feature::sse4_1); - enable(proc_info_ecx, 20, Feature::sse4_2); - enable(proc_info_ecx, 22, Feature::movbe); - enable(proc_info_ecx, 23, Feature::popcnt); - enable(proc_info_ecx, 25, Feature::aes); - let f16c = enable(proc_info_ecx, 29, Feature::f16c); - enable(proc_info_ecx, 30, Feature::rdrand); - enable(extended_features_ebx, 18, Feature::rdseed); - enable(extended_features_ebx, 19, Feature::adx); - enable(extended_features_ebx, 11, Feature::rtm); - enable(proc_info_edx, 4, Feature::tsc); - enable(proc_info_edx, 23, Feature::mmx); - enable(proc_info_edx, 24, Feature::fxsr); - enable(proc_info_edx, 25, Feature::sse); - enable(proc_info_edx, 26, Feature::sse2); - enable(extended_features_ebx, 29, Feature::sha); - - enable(extended_features_ecx, 8, Feature::gfni); - enable(extended_features_ecx, 9, Feature::vaes); - enable(extended_features_ecx, 10, Feature::vpclmulqdq); - - enable(extended_features_ebx, 3, Feature::bmi1); - enable(extended_features_ebx, 8, Feature::bmi2); - - enable(extended_features_ebx, 9, Feature::ermsb); - - enable(extended_features_eax_leaf_1, 31, Feature::movrs); - - // Detect if CPUID.19h available - if bit::test(extended_features_ecx as usize, 23) { - let CpuidResult { ebx, .. } = unsafe { __cpuid(0x19) }; - enable(ebx, 0, Feature::kl); - enable(ebx, 2, Feature::widekl); - } - - // `XSAVE` and `AVX` support: - let cpu_xsave = bit::test(proc_info_ecx as usize, 26); - if cpu_xsave { - // 0. Here the CPU supports `XSAVE`. - - // 1. Detect `OSXSAVE`, that is, whether the OS is AVX enabled and - // supports saving the state of the AVX/AVX2 vector registers on - // context-switches, see: - // - // - [intel: is avx enabled?][is_avx_enabled], - // - [mozilla: sse.cpp][mozilla_sse_cpp]. - // - // [is_avx_enabled]: https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled - // [mozilla_sse_cpp]: https://hg.mozilla.org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190 - let cpu_osxsave = bit::test(proc_info_ecx as usize, 27); - - if cpu_osxsave { - // 2. The OS must have signaled the CPU that it supports saving and - // restoring the: - // - // * SSE -> `XCR0.SSE[1]` - // * AVX -> `XCR0.AVX[2]` - // * AVX-512 -> `XCR0.AVX-512[7:5]`. - // * AMX -> `XCR0.AMX[18:17]` - // - // by setting the corresponding bits of `XCR0` to `1`. - // - // This is safe because the CPU supports `xsave` - // and the OS has set `osxsave`. - let xcr0 = unsafe { _xgetbv(0) }; - // Test `XCR0.SSE[1]` and `XCR0.AVX[2]` with the mask `0b110 == 6`: - let os_avx_support = xcr0 & 6 == 6; - // Test `XCR0.AVX-512[7:5]` with the mask `0b1110_0000 == 0xe0`: - let os_avx512_support = xcr0 & 0xe0 == 0xe0; - // Test `XCR0.AMX[18:17]` with the mask `0b110_0000_0000_0000_0000 == 0x60000` - let os_amx_support = xcr0 & 0x60000 == 0x60000; - - // Only if the OS and the CPU support saving/restoring the AVX - // registers we enable `xsave` support: - if os_avx_support { - // See "13.3 ENABLING THE XSAVE FEATURE SET AND XSAVE-ENABLED - // FEATURES" in the "Intel® 64 and IA-32 Architectures Software - // Developer’s Manual, Volume 1: Basic Architecture": - // - // "Software enables the XSAVE feature set by setting - // CR4.OSXSAVE[bit 18] to 1 (e.g., with the MOV to CR4 - // instruction). If this bit is 0, execution of any of XGETBV, - // XRSTOR, XRSTORS, XSAVE, XSAVEC, XSAVEOPT, XSAVES, and XSETBV - // causes an invalid-opcode exception (#UD)" - // - enable(proc_info_ecx, 26, Feature::xsave); - - // For `xsaveopt`, `xsavec`, and `xsaves` we need to query: - // Processor Extended State Enumeration Sub-leaf (EAX = 0DH, - // ECX = 1): - if max_basic_leaf >= 0xd { - let CpuidResult { - eax: proc_extended_state1_eax, - .. - } = unsafe { __cpuid_count(0xd_u32, 1) }; - enable(proc_extended_state1_eax, 0, Feature::xsaveopt); - enable(proc_extended_state1_eax, 1, Feature::xsavec); - enable(proc_extended_state1_eax, 3, Feature::xsaves); - } - - // FMA (uses 256-bit wide registers): - let fma = enable(proc_info_ecx, 12, Feature::fma); - - // And AVX/AVX2: - enable(proc_info_ecx, 28, Feature::avx); - enable(extended_features_ebx, 5, Feature::avx2); - - // "Short" versions of AVX512 instructions - enable(extended_features_eax_leaf_1, 4, Feature::avxvnni); - enable(extended_features_eax_leaf_1, 23, Feature::avxifma); - enable(extended_features_edx_leaf_1, 4, Feature::avxvnniint8); - enable(extended_features_edx_leaf_1, 5, Feature::avxneconvert); - enable(extended_features_edx_leaf_1, 10, Feature::avxvnniint16); - - enable(extended_features_eax_leaf_1, 0, Feature::sha512); - enable(extended_features_eax_leaf_1, 1, Feature::sm3); - enable(extended_features_eax_leaf_1, 2, Feature::sm4); - - // For AVX-512 the OS also needs to support saving/restoring - // the extended state, only then we enable AVX-512 support: - // Also, Rust makes `avx512f` imply `fma` and `f16c`, because - // otherwise the assembler is broken. But Intel doesn't guarantee - // that `fma` and `f16c` are available with `avx512f`, so we - // need to check for them separately. - if os_avx512_support && f16c && fma { - enable(extended_features_ebx, 16, Feature::avx512f); - enable(extended_features_ebx, 17, Feature::avx512dq); - enable(extended_features_ebx, 21, Feature::avx512ifma); - enable(extended_features_ebx, 26, Feature::avx512pf); - enable(extended_features_ebx, 27, Feature::avx512er); - enable(extended_features_ebx, 28, Feature::avx512cd); - enable(extended_features_ebx, 30, Feature::avx512bw); - enable(extended_features_ebx, 31, Feature::avx512vl); - enable(extended_features_ecx, 1, Feature::avx512vbmi); - enable(extended_features_ecx, 6, Feature::avx512vbmi2); - enable(extended_features_ecx, 11, Feature::avx512vnni); - enable(extended_features_ecx, 12, Feature::avx512bitalg); - enable(extended_features_ecx, 14, Feature::avx512vpopcntdq); - enable(extended_features_edx, 8, Feature::avx512vp2intersect); - enable(extended_features_edx, 23, Feature::avx512fp16); - enable(extended_features_eax_leaf_1, 5, Feature::avx512bf16); - } - } - - if os_amx_support { - enable(extended_features_edx, 24, Feature::amx_tile); - enable(extended_features_edx, 25, Feature::amx_int8); - enable(extended_features_edx, 22, Feature::amx_bf16); - enable(extended_features_eax_leaf_1, 21, Feature::amx_fp16); - enable(extended_features_edx_leaf_1, 8, Feature::amx_complex); - - if max_basic_leaf >= 0x1e { - let CpuidResult { - eax: amx_feature_flags_eax, - .. - } = unsafe { __cpuid_count(0x1e_u32, 1) }; - - enable(amx_feature_flags_eax, 4, Feature::amx_fp8); - enable(amx_feature_flags_eax, 5, Feature::amx_transpose); - enable(amx_feature_flags_eax, 6, Feature::amx_tf32); - enable(amx_feature_flags_eax, 7, Feature::amx_avx512); - enable(amx_feature_flags_eax, 8, Feature::amx_movrs); - } - } - } - } - - // This detects ABM on AMD CPUs and LZCNT on Intel CPUs. - // On intel CPUs with popcnt, lzcnt implements the - // "missing part" of ABM, so we map both to the same - // internal feature. - // - // The `is_x86_feature_detected!("lzcnt")` macro then - // internally maps to Feature::abm. - enable(extended_proc_info_ecx, 5, Feature::lzcnt); - - // As Hygon Dhyana originates from AMD technology and shares most of the architecture with - // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series - // number(Family 18h). - // - // For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD - // family 17h. - // - // Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf. - // Related Hygon kernel patch can be found on - // http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn - if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" { - // These features are available on AMD arch CPUs: - enable(extended_proc_info_ecx, 6, Feature::sse4a); - enable(extended_proc_info_ecx, 21, Feature::tbm); - enable(extended_proc_info_ecx, 11, Feature::xop); - } - } - - // Unfortunately, some Skylake chips erroneously report support for BMI1 and - // BMI2 without actual support. These chips don't support AVX, and it seems - // that all Intel chips with non-erroneous support BMI do (I didn't check - // other vendors), so we can disable these flags for chips that don't also - // report support for AVX. - // - // It's possible this will pessimize future chips that do support BMI and - // not AVX, but this seems minor compared to a hard crash you get when - // executing an unsupported instruction (to put it another way, it's safe - // for us to under-report CPU features, but not to over-report them). Still, - // to limit any impact this may have in the future, we only do this for - // Intel chips, as it's a bug only present in their chips. - // - // This bug is documented as `SKL052` in the errata section of this document: - // http://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/desktop-6th-gen-core-family-spec-update.pdf - if vendor_id == *b"GenuineIntel" && !value.test(Feature::avx as u32) { - value.unset(Feature::bmi1 as u32); - value.unset(Feature::bmi2 as u32); - } - - value -} diff --git a/library/stdarch/crates/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv b/library/stdarch/crates/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv deleted file mode 100644 index ec826afcf38..00000000000 Binary files a/library/stdarch/crates/std_detect/src/detect/test_data/linux-artificial-aarch64.auxv and /dev/null differ diff --git a/library/stdarch/crates/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv b/library/stdarch/crates/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv deleted file mode 100644 index 95537b73f20..00000000000 Binary files a/library/stdarch/crates/std_detect/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv and /dev/null differ diff --git a/library/stdarch/crates/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv b/library/stdarch/crates/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv deleted file mode 100644 index 1d87264b221..00000000000 Binary files a/library/stdarch/crates/std_detect/src/detect/test_data/linux-hwcap2-aarch64.auxv and /dev/null differ diff --git a/library/stdarch/crates/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv b/library/stdarch/crates/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv deleted file mode 100644 index 35f01cc767c..00000000000 Binary files a/library/stdarch/crates/std_detect/src/detect/test_data/linux-no-hwcap2-aarch64.auxv and /dev/null differ diff --git a/library/stdarch/crates/std_detect/src/detect/test_data/linux-rpi3.auxv b/library/stdarch/crates/std_detect/src/detect/test_data/linux-rpi3.auxv deleted file mode 100644 index 0538e661f63..00000000000 Binary files a/library/stdarch/crates/std_detect/src/detect/test_data/linux-rpi3.auxv and /dev/null differ diff --git a/library/stdarch/crates/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv b/library/stdarch/crates/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv deleted file mode 100644 index 75abc02d178..00000000000 Binary files a/library/stdarch/crates/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv and /dev/null differ diff --git a/library/stdarch/crates/std_detect/src/lib.rs b/library/stdarch/crates/std_detect/src/lib.rs deleted file mode 100644 index ab1b77bad5b..00000000000 --- a/library/stdarch/crates/std_detect/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Run-time feature detection for the Rust standard library. -//! -//! To detect whether a feature is enabled in the system running the binary -//! use one of the appropriate macro for the target: -//! -//! * `x86` and `x86_64`: [`is_x86_feature_detected`] -//! * `arm`: [`is_arm_feature_detected`] -//! * `aarch64`: [`is_aarch64_feature_detected`] -//! * `riscv`: [`is_riscv_feature_detected`] -//! * `mips`: [`is_mips_feature_detected`] -//! * `mips64`: [`is_mips64_feature_detected`] -//! * `powerpc`: [`is_powerpc_feature_detected`] -//! * `powerpc64`: [`is_powerpc64_feature_detected`] -//! * `loongarch`: [`is_loongarch_feature_detected`] -//! * `s390x`: [`is_s390x_feature_detected`] - -#![unstable(feature = "stdarch_internal", issue = "none")] -#![feature(staged_api, doc_cfg, allow_internal_unstable)] -#![deny(rust_2018_idioms)] -#![allow(clippy::shadow_reuse)] -#![cfg_attr(test, allow(unused_imports))] -#![no_std] -#![allow(internal_features)] - -#[cfg(test)] -#[macro_use] -extern crate std; - -// rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare> -#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))] -#[cfg(feature = "std_detect_file_io")] -extern crate alloc; - -#[doc(hidden)] -#[unstable(feature = "stdarch_internal", issue = "none")] -pub mod detect; diff --git a/library/stdarch/crates/std_detect/tests/cpu-detection.rs b/library/stdarch/crates/std_detect/tests/cpu-detection.rs deleted file mode 100644 index 7976aedc758..00000000000 --- a/library/stdarch/crates/std_detect/tests/cpu-detection.rs +++ /dev/null @@ -1,354 +0,0 @@ -#![allow(internal_features)] -#![feature(stdarch_internal)] -#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))] -#![cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - feature(stdarch_aarch64_feature_detection) -)] -#![cfg_attr( - any(target_arch = "riscv32", target_arch = "riscv64"), - feature(stdarch_riscv_feature_detection) -)] -#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))] -#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))] -#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))] -#![allow(clippy::unwrap_used, clippy::use_debug, clippy::print_stdout)] - -#[cfg_attr( - any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "arm64ec", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ), - macro_use -)] -extern crate std_detect; - -#[test] -fn all() { - for (f, e) in std_detect::detect::features() { - println!("{f}: {e}"); - } -} - -#[test] -#[cfg(all(target_arch = "arm", target_os = "freebsd"))] -fn arm_freebsd() { - println!("neon: {}", is_arm_feature_detected!("neon")); - println!("pmull: {}", is_arm_feature_detected!("pmull")); - println!("crc: {}", is_arm_feature_detected!("crc")); - println!("aes: {}", is_arm_feature_detected!("aes")); - println!("sha2: {}", is_arm_feature_detected!("sha2")); -} - -#[test] -#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))] -fn arm_linux() { - println!("neon: {}", is_arm_feature_detected!("neon")); - println!("pmull: {}", is_arm_feature_detected!("pmull")); - println!("crc: {}", is_arm_feature_detected!("crc")); - println!("aes: {}", is_arm_feature_detected!("aes")); - println!("sha2: {}", is_arm_feature_detected!("sha2")); - println!("dotprod: {}", is_arm_feature_detected!("dotprod")); - println!("i8mm: {}", is_arm_feature_detected!("i8mm")); -} - -#[test] -#[cfg(all( - target_arch = "aarch64", - any(target_os = "linux", target_os = "android") -))] -fn aarch64_linux() { - println!("asimd: {}", is_aarch64_feature_detected!("asimd")); - println!("neon: {}", is_aarch64_feature_detected!("neon")); - println!("pmull: {}", is_aarch64_feature_detected!("pmull")); - println!("fp: {}", is_aarch64_feature_detected!("fp")); - println!("fp16: {}", is_aarch64_feature_detected!("fp16")); - println!("sve: {}", is_aarch64_feature_detected!("sve")); - println!("crc: {}", is_aarch64_feature_detected!("crc")); - println!("lse: {}", is_aarch64_feature_detected!("lse")); - println!("lse2: {}", is_aarch64_feature_detected!("lse2")); - println!("lse128: {}", is_aarch64_feature_detected!("lse128")); - println!("rdm: {}", is_aarch64_feature_detected!("rdm")); - println!("rcpc: {}", is_aarch64_feature_detected!("rcpc")); - println!("rcpc2: {}", is_aarch64_feature_detected!("rcpc2")); - println!("rcpc3: {}", is_aarch64_feature_detected!("rcpc3")); - println!("dotprod: {}", is_aarch64_feature_detected!("dotprod")); - println!("tme: {}", is_aarch64_feature_detected!("tme")); - println!("fhm: {}", is_aarch64_feature_detected!("fhm")); - println!("dit: {}", is_aarch64_feature_detected!("dit")); - println!("flagm: {}", is_aarch64_feature_detected!("flagm")); - println!("flagm2: {}", is_aarch64_feature_detected!("flagm2")); - println!("ssbs: {}", is_aarch64_feature_detected!("ssbs")); - println!("sb: {}", is_aarch64_feature_detected!("sb")); - println!("paca: {}", is_aarch64_feature_detected!("paca")); - println!("pacg: {}", is_aarch64_feature_detected!("pacg")); - // println!("pauth-lr: {}", is_aarch64_feature_detected!("pauth-lr")); - println!("dpb: {}", is_aarch64_feature_detected!("dpb")); - println!("dpb2: {}", is_aarch64_feature_detected!("dpb2")); - println!("sve-b16b16: {}", is_aarch64_feature_detected!("sve-b16b16")); - println!("sve2: {}", is_aarch64_feature_detected!("sve2")); - println!("sve2p1: {}", is_aarch64_feature_detected!("sve2p1")); - println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes")); - println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4")); - println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3")); - println!( - "sve2-bitperm: {}", - is_aarch64_feature_detected!("sve2-bitperm") - ); - println!("frintts: {}", is_aarch64_feature_detected!("frintts")); - println!("i8mm: {}", is_aarch64_feature_detected!("i8mm")); - println!("f32mm: {}", is_aarch64_feature_detected!("f32mm")); - println!("f64mm: {}", is_aarch64_feature_detected!("f64mm")); - println!("bf16: {}", is_aarch64_feature_detected!("bf16")); - println!("rand: {}", is_aarch64_feature_detected!("rand")); - println!("bti: {}", is_aarch64_feature_detected!("bti")); - println!("mte: {}", is_aarch64_feature_detected!("mte")); - println!("jsconv: {}", is_aarch64_feature_detected!("jsconv")); - println!("fcma: {}", is_aarch64_feature_detected!("fcma")); - println!("aes: {}", is_aarch64_feature_detected!("aes")); - println!("sha2: {}", is_aarch64_feature_detected!("sha2")); - println!("sha3: {}", is_aarch64_feature_detected!("sha3")); - println!("sm4: {}", is_aarch64_feature_detected!("sm4")); - println!("hbc: {}", is_aarch64_feature_detected!("hbc")); - println!("mops: {}", is_aarch64_feature_detected!("mops")); - println!("ecv: {}", is_aarch64_feature_detected!("ecv")); - println!("cssc: {}", is_aarch64_feature_detected!("cssc")); - println!("fpmr: {}", is_aarch64_feature_detected!("fpmr")); - println!("lut: {}", is_aarch64_feature_detected!("lut")); - println!("faminmax: {}", is_aarch64_feature_detected!("faminmax")); - println!("fp8: {}", is_aarch64_feature_detected!("fp8")); - println!("fp8fma: {}", is_aarch64_feature_detected!("fp8fma")); - println!("fp8dot4: {}", is_aarch64_feature_detected!("fp8dot4")); - println!("fp8dot2: {}", is_aarch64_feature_detected!("fp8dot2")); - println!("wfxt: {}", is_aarch64_feature_detected!("wfxt")); - println!("sme: {}", is_aarch64_feature_detected!("sme")); - println!("sme-b16b16: {}", is_aarch64_feature_detected!("sme-b16b16")); - println!("sme-i16i64: {}", is_aarch64_feature_detected!("sme-i16i64")); - println!("sme-f64f64: {}", is_aarch64_feature_detected!("sme-f64f64")); - println!("sme-fa64: {}", is_aarch64_feature_detected!("sme-fa64")); - println!("sme2: {}", is_aarch64_feature_detected!("sme2")); - println!("sme2p1: {}", is_aarch64_feature_detected!("sme2p1")); - println!("sme-f16f16: {}", is_aarch64_feature_detected!("sme-f16f16")); - println!("sme-lutv2: {}", is_aarch64_feature_detected!("sme-lutv2")); - println!("sme-f8f16: {}", is_aarch64_feature_detected!("sme-f8f16")); - println!("sme-f8f32: {}", is_aarch64_feature_detected!("sme-f8f32")); - println!( - "ssve-fp8fma: {}", - is_aarch64_feature_detected!("ssve-fp8fma") - ); - println!( - "ssve-fp8dot4: {}", - is_aarch64_feature_detected!("ssve-fp8dot4") - ); - println!( - "ssve-fp8dot2: {}", - is_aarch64_feature_detected!("ssve-fp8dot2") - ); -} - -#[test] -#[cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - target_os = "windows" -))] -fn aarch64_windows() { - println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); - println!("fp: {:?}", is_aarch64_feature_detected!("fp")); - println!("crc: {:?}", is_aarch64_feature_detected!("crc")); - println!("lse: {:?}", is_aarch64_feature_detected!("lse")); - println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); - println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv")); - println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); - println!("aes: {:?}", is_aarch64_feature_detected!("aes")); - println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); - println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); -} - -#[test] -#[cfg(all( - target_arch = "aarch64", - any(target_os = "freebsd", target_os = "openbsd") -))] -fn aarch64_bsd() { - println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); - println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); - println!("fp: {:?}", is_aarch64_feature_detected!("fp")); - println!("fp16: {:?}", is_aarch64_feature_detected!("fp16")); - println!("sve: {:?}", is_aarch64_feature_detected!("sve")); - println!("crc: {:?}", is_aarch64_feature_detected!("crc")); - println!("lse: {:?}", is_aarch64_feature_detected!("lse")); - println!("lse2: {:?}", is_aarch64_feature_detected!("lse2")); - println!("rdm: {:?}", is_aarch64_feature_detected!("rdm")); - println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); - println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); - println!("tme: {:?}", is_aarch64_feature_detected!("tme")); - println!("paca: {:?}", is_aarch64_feature_detected!("paca")); - println!("pacg: {:?}", is_aarch64_feature_detected!("pacg")); - println!("aes: {:?}", is_aarch64_feature_detected!("aes")); - println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); -} - -#[test] -#[cfg(all(target_arch = "aarch64", target_vendor = "apple"))] -fn aarch64_darwin() { - println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); - println!("fp: {:?}", is_aarch64_feature_detected!("fp")); - println!("fp16: {:?}", is_aarch64_feature_detected!("fp16")); - println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); - println!("crc: {:?}", is_aarch64_feature_detected!("crc")); - println!("lse: {:?}", is_aarch64_feature_detected!("lse")); - println!("lse2: {:?}", is_aarch64_feature_detected!("lse2")); - println!("rdm: {:?}", is_aarch64_feature_detected!("rdm")); - println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); - println!("rcpc2: {:?}", is_aarch64_feature_detected!("rcpc2")); - println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); - println!("fhm: {:?}", is_aarch64_feature_detected!("fhm")); - println!("flagm: {:?}", is_aarch64_feature_detected!("flagm")); - println!("ssbs: {:?}", is_aarch64_feature_detected!("ssbs")); - println!("sb: {:?}", is_aarch64_feature_detected!("sb")); - println!("paca: {:?}", is_aarch64_feature_detected!("paca")); - println!("dpb: {:?}", is_aarch64_feature_detected!("dpb")); - println!("dpb2: {:?}", is_aarch64_feature_detected!("dpb2")); - println!("frintts: {:?}", is_aarch64_feature_detected!("frintts")); - println!("i8mm: {:?}", is_aarch64_feature_detected!("i8mm")); - println!("bf16: {:?}", is_aarch64_feature_detected!("bf16")); - println!("bti: {:?}", is_aarch64_feature_detected!("bti")); - println!("fcma: {:?}", is_aarch64_feature_detected!("fcma")); - println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv")); - println!("aes: {:?}", is_aarch64_feature_detected!("aes")); - println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); - println!("sha3: {:?}", is_aarch64_feature_detected!("sha3")); -} - -#[test] -#[cfg(all( - any(target_arch = "riscv32", target_arch = "riscv64"), - any(target_os = "linux", target_os = "android") -))] -fn riscv_linux() { - println!("rv32i: {}", is_riscv_feature_detected!("rv32i")); - println!("rv32e: {}", is_riscv_feature_detected!("rv32e")); - println!("rv64i: {}", is_riscv_feature_detected!("rv64i")); - println!("rv128i: {}", is_riscv_feature_detected!("rv128i")); - println!( - "unaligned-scalar-mem: {}", - is_riscv_feature_detected!("unaligned-scalar-mem") - ); - println!( - "unaligned-vector-mem: {}", - is_riscv_feature_detected!("unaligned-vector-mem") - ); - println!("zicsr: {}", is_riscv_feature_detected!("zicsr")); - println!("zicntr: {}", is_riscv_feature_detected!("zicntr")); - println!("zihpm: {}", is_riscv_feature_detected!("zihpm")); - println!("zifencei: {}", is_riscv_feature_detected!("zifencei")); - println!("zihintntl: {}", is_riscv_feature_detected!("zihintntl")); - println!("zihintpause: {}", is_riscv_feature_detected!("zihintpause")); - println!("zimop: {}", is_riscv_feature_detected!("zimop")); - println!("zicbom: {}", is_riscv_feature_detected!("zicbom")); - println!("zicboz: {}", is_riscv_feature_detected!("zicboz")); - println!("zicond: {}", is_riscv_feature_detected!("zicond")); - println!("m: {}", is_riscv_feature_detected!("m")); - println!("a: {}", is_riscv_feature_detected!("a")); - println!("zalrsc: {}", is_riscv_feature_detected!("zalrsc")); - println!("zaamo: {}", is_riscv_feature_detected!("zaamo")); - println!("zawrs: {}", is_riscv_feature_detected!("zawrs")); - println!("zacas: {}", is_riscv_feature_detected!("zacas")); - println!("zam: {}", is_riscv_feature_detected!("zam")); - println!("ztso: {}", is_riscv_feature_detected!("ztso")); - println!("f: {}", is_riscv_feature_detected!("f")); - println!("d: {}", is_riscv_feature_detected!("d")); - println!("q: {}", is_riscv_feature_detected!("q")); - println!("zfh: {}", is_riscv_feature_detected!("zfh")); - println!("zfhmin: {}", is_riscv_feature_detected!("zfhmin")); - println!("zfa: {}", is_riscv_feature_detected!("zfa")); - println!("zfbfmin: {}", is_riscv_feature_detected!("zfbfmin")); - println!("zfinx: {}", is_riscv_feature_detected!("zfinx")); - println!("zdinx: {}", is_riscv_feature_detected!("zdinx")); - println!("zhinx: {}", is_riscv_feature_detected!("zhinx")); - println!("zhinxmin: {}", is_riscv_feature_detected!("zhinxmin")); - println!("c: {}", is_riscv_feature_detected!("c")); - println!("zca: {}", is_riscv_feature_detected!("zca")); - println!("zcf: {}", is_riscv_feature_detected!("zcf")); - println!("zcd: {}", is_riscv_feature_detected!("zcd")); - println!("zcb: {}", is_riscv_feature_detected!("zcb")); - println!("zcmop: {}", is_riscv_feature_detected!("zcmop")); - println!("b: {}", is_riscv_feature_detected!("b")); - println!("zba: {}", is_riscv_feature_detected!("zba")); - println!("zbb: {}", is_riscv_feature_detected!("zbb")); - println!("zbc: {}", is_riscv_feature_detected!("zbc")); - println!("zbs: {}", is_riscv_feature_detected!("zbs")); - println!("zbkb: {}", is_riscv_feature_detected!("zbkb")); - println!("zbkc: {}", is_riscv_feature_detected!("zbkc")); - println!("zbkx: {}", is_riscv_feature_detected!("zbkx")); - println!("zknd: {}", is_riscv_feature_detected!("zknd")); - println!("zkne: {}", is_riscv_feature_detected!("zkne")); - println!("zknh: {}", is_riscv_feature_detected!("zknh")); - println!("zksed: {}", is_riscv_feature_detected!("zksed")); - println!("zksh: {}", is_riscv_feature_detected!("zksh")); - println!("zkr: {}", is_riscv_feature_detected!("zkr")); - println!("zkn: {}", is_riscv_feature_detected!("zkn")); - println!("zks: {}", is_riscv_feature_detected!("zks")); - println!("zk: {}", is_riscv_feature_detected!("zk")); - println!("zkt: {}", is_riscv_feature_detected!("zkt")); - println!("v: {}", is_riscv_feature_detected!("v")); - println!("zve32x: {}", is_riscv_feature_detected!("zve32x")); - println!("zve32f: {}", is_riscv_feature_detected!("zve32f")); - println!("zve64x: {}", is_riscv_feature_detected!("zve64x")); - println!("zve64f: {}", is_riscv_feature_detected!("zve64f")); - println!("zve64d: {}", is_riscv_feature_detected!("zve64d")); - println!("zvfh: {}", is_riscv_feature_detected!("zvfh")); - println!("zvfhmin: {}", is_riscv_feature_detected!("zvfhmin")); - println!("zvfbfmin: {}", is_riscv_feature_detected!("zvfbfmin")); - println!("zvfbfwma: {}", is_riscv_feature_detected!("zvfbfwma")); - println!("zvbb: {}", is_riscv_feature_detected!("zvbb")); - println!("zvbc: {}", is_riscv_feature_detected!("zvbc")); - println!("zvkb: {}", is_riscv_feature_detected!("zvkb")); - println!("zvkg: {}", is_riscv_feature_detected!("zvkg")); - println!("zvkned: {}", is_riscv_feature_detected!("zvkned")); - println!("zvknha: {}", is_riscv_feature_detected!("zvknha")); - println!("zvknhb: {}", is_riscv_feature_detected!("zvknhb")); - println!("zvksed: {}", is_riscv_feature_detected!("zvksed")); - println!("zvksh: {}", is_riscv_feature_detected!("zvksh")); - println!("zvkn: {}", is_riscv_feature_detected!("zvkn")); - println!("zvknc: {}", is_riscv_feature_detected!("zvknc")); - println!("zvkng: {}", is_riscv_feature_detected!("zvkng")); - println!("zvks: {}", is_riscv_feature_detected!("zvks")); - println!("zvksc: {}", is_riscv_feature_detected!("zvksc")); - println!("zvksg: {}", is_riscv_feature_detected!("zvksg")); - println!("zvkt: {}", is_riscv_feature_detected!("zvkt")); - println!("j: {}", is_riscv_feature_detected!("j")); - println!("p: {}", is_riscv_feature_detected!("p")); -} - -#[test] -#[cfg(all(target_arch = "powerpc", target_os = "linux"))] -fn powerpc_linux() { - println!("altivec: {}", is_powerpc_feature_detected!("altivec")); - println!("vsx: {}", is_powerpc_feature_detected!("vsx")); - println!("power8: {}", is_powerpc_feature_detected!("power8")); -} - -#[test] -#[cfg(all( - target_arch = "powerpc64", - any(target_os = "linux", target_os = "freebsd"), -))] -fn powerpc64_linux_or_freebsd() { - println!("altivec: {}", is_powerpc64_feature_detected!("altivec")); - println!("vsx: {}", is_powerpc64_feature_detected!("vsx")); - println!("power8: {}", is_powerpc64_feature_detected!("power8")); - println!("power9: {}", is_powerpc64_feature_detected!("power9")); -} - -#[test] -#[cfg(all(target_arch = "s390x", target_os = "linux",))] -fn s390x_linux() { - println!("vector: {}", is_s390x_feature_detected!("vector")); -} diff --git a/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs b/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs deleted file mode 100644 index 2fee0abdd57..00000000000 --- a/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs +++ /dev/null @@ -1,109 +0,0 @@ -#![allow(internal_features)] -#![cfg_attr( - any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "arm64ec", - target_arch = "x86", - target_arch = "x86_64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "loongarch32", - target_arch = "loongarch64" - ), - feature(stdarch_internal) -)] -#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))] -#![cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - feature(stdarch_aarch64_feature_detection) -)] -#![cfg_attr( - any(target_arch = "powerpc", target_arch = "powerpc64"), - feature(stdarch_powerpc_feature_detection) -)] -#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))] -#![cfg_attr( - any(target_arch = "riscv32", target_arch = "riscv64"), - feature(stdarch_riscv_feature_detection) -)] -#![cfg_attr( - any(target_arch = "loongarch32", target_arch = "loongarch64"), - feature(stdarch_loongarch_feature_detection) -)] - -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "arm64ec", - target_arch = "x86", - target_arch = "x86_64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "loongarch32", - target_arch = "loongarch64" -))] -#[macro_use] -extern crate std_detect; - -#[test] -#[cfg(target_arch = "arm")] -fn arm() { - let _ = is_arm_feature_detected!("neon"); - let _ = is_arm_feature_detected!("neon",); -} - -#[test] -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] -fn aarch64() { - let _ = is_aarch64_feature_detected!("fp"); - let _ = is_aarch64_feature_detected!("fp",); -} - -#[test] -#[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] -fn loongarch() { - let _ = is_loongarch_feature_detected!("lsx"); - let _ = is_loongarch_feature_detected!("lsx",); -} - -#[test] -#[cfg(target_arch = "powerpc")] -fn powerpc() { - let _ = is_powerpc_feature_detected!("altivec"); - let _ = is_powerpc_feature_detected!("altivec",); -} - -#[test] -#[cfg(target_arch = "powerpc64")] -fn powerpc64() { - let _ = is_powerpc64_feature_detected!("altivec"); - let _ = is_powerpc64_feature_detected!("altivec",); -} - -#[test] -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -fn riscv() { - let _ = is_riscv_feature_detected!("zk"); - let _ = is_riscv_feature_detected!("zk",); -} - -#[test] -#[cfg(target_arch = "s390x")] -fn s390x() { - let _ = is_s390x_feature_detected!("vector"); - let _ = is_s390x_feature_detected!("vector",); -} - -#[test] -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn x86() { - let _ = is_x86_feature_detected!("sse"); - let _ = is_x86_feature_detected!("sse",); -} diff --git a/library/stdarch/crates/std_detect/tests/x86-specific.rs b/library/stdarch/crates/std_detect/tests/x86-specific.rs deleted file mode 100644 index d9ec79821ba..00000000000 --- a/library/stdarch/crates/std_detect/tests/x86-specific.rs +++ /dev/null @@ -1,117 +0,0 @@ -#![cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#![allow(internal_features)] -#![feature( - stdarch_internal, - x86_amx_intrinsics, - xop_target_feature, - movrs_target_feature -)] - -#[macro_use] -extern crate std_detect; - -#[test] -fn dump() { - println!("aes: {:?}", is_x86_feature_detected!("aes")); - println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); - println!("rdrand: {:?}", is_x86_feature_detected!("rdrand")); - println!("rdseed: {:?}", is_x86_feature_detected!("rdseed")); - println!("tsc: {:?}", is_x86_feature_detected!("tsc")); - println!("sse: {:?}", is_x86_feature_detected!("sse")); - println!("sse2: {:?}", is_x86_feature_detected!("sse2")); - println!("sse3: {:?}", is_x86_feature_detected!("sse3")); - println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); - println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1")); - println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2")); - println!("sse4a: {:?}", is_x86_feature_detected!("sse4a")); - println!("sha: {:?}", is_x86_feature_detected!("sha")); - println!("f16c: {:?}", is_x86_feature_detected!("f16c")); - println!("avx: {:?}", is_x86_feature_detected!("avx")); - println!("avx2: {:?}", is_x86_feature_detected!("avx2")); - println!("sha512: {:?}", is_x86_feature_detected!("sha512")); - println!("sm3: {:?}", is_x86_feature_detected!("sm3")); - println!("sm4: {:?}", is_x86_feature_detected!("sm4")); - println!("avx512f: {:?}", is_x86_feature_detected!("avx512f")); - println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd")); - println!("avx512er: {:?}", is_x86_feature_detected!("avx512er")); - println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf")); - println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw")); - println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq")); - println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl")); - println!("avx512_ifma: {:?}", is_x86_feature_detected!("avx512ifma")); - println!("avx512vbmi {:?}", is_x86_feature_detected!("avx512vbmi")); - println!( - "avx512_vpopcntdq: {:?}", - is_x86_feature_detected!("avx512vpopcntdq") - ); - println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2")); - println!("gfni: {:?}", is_x86_feature_detected!("gfni")); - println!("vaes: {:?}", is_x86_feature_detected!("vaes")); - println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq")); - println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni")); - println!( - "avx512bitalg: {:?}", - is_x86_feature_detected!("avx512bitalg") - ); - println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16")); - println!( - "avx512vp2intersect: {:?}", - is_x86_feature_detected!("avx512vp2intersect") - ); - println!("avx512fp16: {:?}", is_x86_feature_detected!("avx512fp16")); - println!("fma: {:?}", is_x86_feature_detected!("fma")); - println!("abm: {:?}", is_x86_feature_detected!("abm")); - println!("bmi: {:?}", is_x86_feature_detected!("bmi1")); - println!("bmi2: {:?}", is_x86_feature_detected!("bmi2")); - println!("tbm: {:?}", is_x86_feature_detected!("tbm")); - println!("popcnt: {:?}", is_x86_feature_detected!("popcnt")); - println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); - println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); - println!("xsave: {:?}", is_x86_feature_detected!("xsave")); - println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt")); - println!("xsaves: {:?}", is_x86_feature_detected!("xsaves")); - println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); - println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b")); - println!("adx: {:?}", is_x86_feature_detected!("adx")); - println!("rtm: {:?}", is_x86_feature_detected!("rtm")); - println!("movbe: {:?}", is_x86_feature_detected!("movbe")); - println!("avxvnni: {:?}", is_x86_feature_detected!("avxvnni")); - println!("avxvnniint8: {:?}", is_x86_feature_detected!("avxvnniint8")); - println!( - "avxneconvert: {:?}", - is_x86_feature_detected!("avxneconvert") - ); - println!("avxifma: {:?}", is_x86_feature_detected!("avxifma")); - println!( - "avxvnniint16: {:?}", - is_x86_feature_detected!("avxvnniint16") - ); - println!("amx-bf16: {:?}", is_x86_feature_detected!("amx-bf16")); - println!("amx-tile: {:?}", is_x86_feature_detected!("amx-tile")); - println!("amx-int8: {:?}", is_x86_feature_detected!("amx-int8")); - println!("amx-fp16: {:?}", is_x86_feature_detected!("amx-fp16")); - println!("amx-complex: {:?}", is_x86_feature_detected!("amx-complex")); - println!("xop: {:?}", is_x86_feature_detected!("xop")); - println!("kl: {:?}", is_x86_feature_detected!("kl")); - println!("widekl: {:?}", is_x86_feature_detected!("widekl")); - println!("movrs: {:?}", is_x86_feature_detected!("movrs")); - println!("amx-fp8: {:?}", is_x86_feature_detected!("amx-fp8")); - println!( - "amx-transpose: {:?}", - is_x86_feature_detected!("amx-transpose") - ); - println!("amx-tf32: {:?}", is_x86_feature_detected!("amx-tf32")); - println!("amx-avx512: {:?}", is_x86_feature_detected!("amx-avx512")); - println!("amx-movrs: {:?}", is_x86_feature_detected!("amx-movrs")); -} - -#[test] -#[allow(deprecated)] -fn x86_deprecated() { - println!("avx512gfni {:?}", is_x86_feature_detected!("avx512gfni")); - println!("avx512vaes {:?}", is_x86_feature_detected!("avx512vaes")); - println!( - "avx512vpclmulqdq {:?}", - is_x86_feature_detected!("avx512vpclmulqdq") - ); -} -- cgit 1.4.1-3-g733a5 From b23ab7888a06f548e8d9a5951e97cb68399e31b3 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 09:51:28 +0200 Subject: Make `std_detect` a direct dependency of `std` --- library/Cargo.lock | 4 ++-- library/std/Cargo.toml | 7 ++----- library/std_detect/Cargo.toml | 12 +++--------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 8b5275e5065..94155e08398 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -340,10 +340,10 @@ dependencies = [ name = "std_detect" version = "0.1.5" dependencies = [ + "alloc", "cfg-if", + "core", "libc", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", ] [[package]] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 5c3132a7375..ba1e1f5218a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -23,9 +23,7 @@ unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } -std_detect = { path = "../stdarch/crates/std_detect", public = true, default-features = false, features = [ - 'rustc-dep-of-std', -] } +std_detect = { path = "../std_detect", public = true } # Dependencies of the `backtrace` crate rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] } @@ -118,8 +116,7 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] debug_refcell = ["core/debug_refcell"] -# Enable std_detect default features for stdarch/crates/std_detect: -# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml +# Enable std_detect features: std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index f990e724125..8d91454726b 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -22,20 +22,14 @@ maintenance = { status = "experimental" } [dependencies] cfg-if = "1.0.0" - -# When built as part of libstd -core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } -alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } +core = { path = "../core" } +alloc = { path = "../alloc" } [target.'cfg(not(windows))'.dependencies] libc = { version = "0.2.0", optional = true, default-features = false } [features] -default = [ "std_detect_dlsym_getauxval", "std_detect_file_io" ] +default = [] std_detect_file_io = [ "libc" ] std_detect_dlsym_getauxval = [ "libc" ] std_detect_env_override = [ "libc" ] -rustc-dep-of-std = [ - "core", - "alloc", -] -- cgit 1.4.1-3-g733a5 From 1057a2213af6fd273da86f13edeae559bfdd587d Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 10:08:50 +0200 Subject: Allow platform-specific code in `std_detect` --- src/tools/tidy/src/pal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index b7d4a331891..5b8b44429bb 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -37,6 +37,7 @@ use crate::walk::{filter_dirs, walk}; // Paths that may contain platform-specific code. const EXCEPTION_PATHS: &[&str] = &[ "library/compiler-builtins", + "library/std_detect", "library/windows_targets", "library/panic_abort", "library/panic_unwind", -- cgit 1.4.1-3-g733a5 From ee6f2c5276c3e19b919abb61693e66b0ded9c8ba Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 10:08:58 +0200 Subject: Reformat `std_detect` --- library/std_detect/src/detect/cache.rs | 38 ++++------------ library/std_detect/src/detect/mod.rs | 1 - library/std_detect/src/detect/os/aarch64.rs | 8 ++-- library/std_detect/src/detect/os/darwin/aarch64.rs | 11 ++--- library/std_detect/src/detect/os/freebsd/auxvec.rs | 7 +-- library/std_detect/src/detect/os/linux/aarch64.rs | 10 +---- .../std_detect/src/detect/os/linux/loongarch.rs | 15 ++----- library/std_detect/src/detect/os/linux/riscv.rs | 11 +---- .../std_detect/src/detect/os/openbsd/aarch64.rs | 4 +- library/std_detect/src/detect/os/x86.rs | 39 +++++------------ library/std_detect/tests/cpu-detection.rs | 50 +++++----------------- library/std_detect/tests/x86-specific.rs | 42 ++++-------------- 12 files changed, 54 insertions(+), 182 deletions(-) diff --git a/library/std_detect/src/detect/cache.rs b/library/std_detect/src/detect/cache.rs index 83bcedea612..1a42e091463 100644 --- a/library/std_detect/src/detect/cache.rs +++ b/library/std_detect/src/detect/cache.rs @@ -3,9 +3,7 @@ #![allow(dead_code)] // not used on all platforms -use core::sync::atomic::Ordering; - -use core::sync::atomic::AtomicUsize; +use core::sync::atomic::{AtomicUsize, Ordering}; /// Sets the `bit` of `x`. #[inline] @@ -40,20 +38,14 @@ impl Initializer { /// Tests the `bit` of the cache. #[inline] pub(crate) fn test(self, bit: u32) -> bool { - debug_assert!( - bit < CACHE_CAPACITY, - "too many features, time to increase the cache size!" - ); + debug_assert!(bit < CACHE_CAPACITY, "too many features, time to increase the cache size!"); test_bit(self.0, bit) } /// Sets the `bit` of the cache. #[inline] pub(crate) fn set(&mut self, bit: u32) { - debug_assert!( - bit < CACHE_CAPACITY, - "too many features, time to increase the cache size!" - ); + debug_assert!(bit < CACHE_CAPACITY, "too many features, time to increase the cache size!"); let v = self.0; self.0 = set_bit(v, bit); } @@ -61,10 +53,7 @@ impl Initializer { /// Unsets the `bit` of the cache. #[inline] pub(crate) fn unset(&mut self, bit: u32) { - debug_assert!( - bit < CACHE_CAPACITY, - "too many features, time to increase the cache size!" - ); + debug_assert!(bit < CACHE_CAPACITY, "too many features, time to increase the cache size!"); let v = self.0; self.0 = unset_bit(v, bit); } @@ -73,11 +62,7 @@ impl Initializer { /// This global variable is a cache of the features supported by the CPU. // Note: the third slot is only used in x86 // Another Slot can be added if needed without any change to `Initializer` -static CACHE: [Cache; 3] = [ - Cache::uninitialized(), - Cache::uninitialized(), - Cache::uninitialized(), -]; +static CACHE: [Cache; 3] = [Cache::uninitialized(), Cache::uninitialized(), Cache::uninitialized()]; /// Feature cache with capacity for `size_of::() * 8 - 1` features. /// @@ -104,19 +89,14 @@ impl Cache { #[inline] pub(crate) fn test(&self, bit: u32) -> Option { let cached = self.0.load(Ordering::Relaxed); - if cached == 0 { - None - } else { - Some(test_bit(cached as u128, bit)) - } + if cached == 0 { None } else { Some(test_bit(cached as u128, bit)) } } /// Initializes the cache. #[inline] fn initialize(&self, value: usize) -> usize { debug_assert_eq!((value & !Cache::MASK), 0); - self.0 - .store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed); + self.0.store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed); value } } @@ -217,7 +197,5 @@ pub(crate) fn test(bit: u32) -> bool { } else { (bit - 2 * Cache::CAPACITY, 2) }; - CACHE[idx] - .test(relative_bit) - .unwrap_or_else(|| detect_and_initialize().test(bit)) + CACHE[idx].test(relative_bit).unwrap_or_else(|| detect_and_initialize().test(bit)) } diff --git a/library/std_detect/src/detect/mod.rs b/library/std_detect/src/detect/mod.rs index a9e9709c1f6..f936a5a1345 100644 --- a/library/std_detect/src/detect/mod.rs +++ b/library/std_detect/src/detect/mod.rs @@ -29,7 +29,6 @@ mod arch; #[doc(hidden)] #[unstable(feature = "stdarch_internal", issue = "none")] pub use self::arch::__is_feature_detected; - pub(crate) use self::arch::Feature; mod bit; diff --git a/library/std_detect/src/detect/os/aarch64.rs b/library/std_detect/src/detect/os/aarch64.rs index 1ff2a17e6e1..c2c754ccf8d 100644 --- a/library/std_detect/src/detect/os/aarch64.rs +++ b/library/std_detect/src/detect/os/aarch64.rs @@ -17,9 +17,10 @@ //! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt) //! - [ARM documentation](https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers?lang=en) -use crate::detect::{Feature, cache}; use core::arch::asm; +use crate::detect::{Feature, cache}; + /// Try to read the features from the system registers. /// /// This will cause SIGILL if the current OS is not trapping the mrs instruction. @@ -104,10 +105,7 @@ pub(crate) fn parse_system_registers( let sha2 = bits_shift(aa64isar0, 15, 12) >= 1; enable_feature(Feature::sha2, asimd && sha1 && sha2); enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1); - enable_feature( - Feature::dotprod, - asimd && bits_shift(aa64isar0, 47, 44) >= 1, - ); + enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1); enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1); } diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs index 44d921689e5..f5409361d93 100644 --- a/library/std_detect/src/detect/os/darwin/aarch64.rs +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -2,9 +2,10 @@ //! //! -use crate::detect::{Feature, cache}; use core::ffi::CStr; +use crate::detect::{Feature, cache}; + #[inline] fn _sysctlbyname(name: &CStr) -> bool { use libc; @@ -14,13 +15,7 @@ fn _sysctlbyname(name: &CStr) -> bool { let enabled_ptr = &mut enabled as *mut i32 as *mut libc::c_void; let ret = unsafe { - libc::sysctlbyname( - name.as_ptr(), - enabled_ptr, - &mut enabled_len, - core::ptr::null_mut(), - 0, - ) + libc::sysctlbyname(name.as_ptr(), enabled_ptr, &mut enabled_len, core::ptr::null_mut(), 0) }; match ret { diff --git a/library/std_detect/src/detect/os/freebsd/auxvec.rs b/library/std_detect/src/detect/os/freebsd/auxvec.rs index 4e72bf22d76..2a7b87c05d1 100644 --- a/library/std_detect/src/detect/os/freebsd/auxvec.rs +++ b/library/std_detect/src/detect/os/freebsd/auxvec.rs @@ -54,11 +54,8 @@ fn archauxv(key: libc::c_int) -> usize { // https://github.com/freebsd/freebsd-src/blob/release/11.4.0/sys/sys/auxv.h // FreeBSD 11 support in std has been removed in Rust 1.75 (https://github.com/rust-lang/rust/pull/114521), // so we can safely use this function. - let res = libc::elf_aux_info( - key, - &mut out as *mut libc::c_ulong as *mut libc::c_void, - OUT_LEN, - ); + let res = + libc::elf_aux_info(key, &mut out as *mut libc::c_ulong as *mut libc::c_void, OUT_LEN); // If elf_aux_info fails, `out` will be left at zero (which is the proper default value). debug_assert!(res == 0 || out == 0); } diff --git a/library/std_detect/src/detect/os/linux/aarch64.rs b/library/std_detect/src/detect/os/linux/aarch64.rs index 22a9cefff7b..0de4beeae8b 100644 --- a/library/std_detect/src/detect/os/linux/aarch64.rs +++ b/library/std_detect/src/detect/os/linux/aarch64.rs @@ -343,14 +343,8 @@ impl AtHwcap { enable_feature(Feature::sve2, sve2); enable_feature(Feature::sve2p1, self.sve2p1 && sve2); // SVE2 extensions require SVE2 and crypto features - enable_feature( - Feature::sve2_aes, - self.sveaes && self.svepmull && sve2 && self.aes, - ); - enable_feature( - Feature::sve2_sm4, - self.svesm4 && sve2 && self.sm3 && self.sm4, - ); + enable_feature(Feature::sve2_aes, self.sveaes && self.svepmull && sve2 && self.aes); + enable_feature(Feature::sve2_sm4, self.svesm4 && sve2 && self.sm3 && self.sm4); enable_feature( Feature::sve2_sha3, self.svesha3 && sve2 && self.sha512 && self.sha3 && self.sha1 && self.sha2, diff --git a/library/std_detect/src/detect/os/linux/loongarch.rs b/library/std_detect/src/detect/os/linux/loongarch.rs index 14cc7a73183..e97fda11d08 100644 --- a/library/std_detect/src/detect/os/linux/loongarch.rs +++ b/library/std_detect/src/detect/os/linux/loongarch.rs @@ -1,8 +1,9 @@ //! Run-time feature detection for LoongArch on Linux. +use core::arch::asm; + use super::auxvec; use crate::detect::{Feature, bit, cache}; -use core::arch::asm; /// Try to read the features from the auxiliary vector. pub(crate) fn detect_features() -> cache::Initializer { @@ -43,16 +44,8 @@ pub(crate) fn detect_features() -> cache::Initializer { // // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h if let Ok(auxv) = auxvec::auxv() { - enable_feature( - &mut value, - Feature::f, - bit::test(cpucfg2, 1) && bit::test(auxv.hwcap, 3), - ); - enable_feature( - &mut value, - Feature::d, - bit::test(cpucfg2, 2) && bit::test(auxv.hwcap, 3), - ); + enable_feature(&mut value, Feature::f, bit::test(cpucfg2, 1) && bit::test(auxv.hwcap, 3)); + enable_feature(&mut value, Feature::d, bit::test(cpucfg2, 2) && bit::test(auxv.hwcap, 3)); enable_feature(&mut value, Feature::lsx, bit::test(auxv.hwcap, 4)); enable_feature(&mut value, Feature::lasx, bit::test(auxv.hwcap, 5)); enable_feature( diff --git a/library/std_detect/src/detect/os/linux/riscv.rs b/library/std_detect/src/detect/os/linux/riscv.rs index db20538af95..dbb3664890e 100644 --- a/library/std_detect/src/detect/os/linux/riscv.rs +++ b/library/std_detect/src/detect/os/linux/riscv.rs @@ -119,16 +119,7 @@ fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool { cpus: *mut libc::c_ulong, flags: libc::c_uint, ) -> libc::c_long { - unsafe { - libc::syscall( - __NR_riscv_hwprobe, - pairs, - pair_count, - cpu_set_size, - cpus, - flags, - ) - } + unsafe { libc::syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_set_size, cpus, flags) } } unsafe { __riscv_hwprobe(out.as_mut_ptr(), out.len(), 0, ptr::null_mut(), 0) == 0 } diff --git a/library/std_detect/src/detect/os/openbsd/aarch64.rs b/library/std_detect/src/detect/os/openbsd/aarch64.rs index cfe4ad10ad6..2fae47b05c4 100644 --- a/library/std_detect/src/detect/os/openbsd/aarch64.rs +++ b/library/std_detect/src/detect/os/openbsd/aarch64.rs @@ -4,8 +4,10 @@ //! https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8 //! https://github.com/golang/go/commit/cd54ef1f61945459486e9eea2f016d99ef1da925 +use core::mem::MaybeUninit; +use core::ptr; + use crate::detect::cache; -use core::{mem::MaybeUninit, ptr}; // Defined in machine/cpu.h. // https://github.com/openbsd/src/blob/72ccc03bd11da614f31f7ff76e3f6fce99bc1c79/sys/arch/arm64/include/cpu.h#L25-L40 diff --git a/library/std_detect/src/detect/os/x86.rs b/library/std_detect/src/detect/os/x86.rs index 8565c2f85e2..20f848ab05c 100644 --- a/library/std_detect/src/detect/os/x86.rs +++ b/library/std_detect/src/detect/os/x86.rs @@ -4,7 +4,6 @@ use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; - use core::mem; use crate::detect::{Feature, bit, cache}; @@ -42,12 +41,7 @@ pub(crate) fn detect_features() -> cache::Initializer { // 0x8000_0000]. - The vendor ID is stored in 12 u8 ascii chars, // returned in EBX, EDX, and ECX (in that order): let (max_basic_leaf, vendor_id) = unsafe { - let CpuidResult { - eax: max_basic_leaf, - ebx, - ecx, - edx, - } = __cpuid(0); + let CpuidResult { eax: max_basic_leaf, ebx, ecx, edx } = __cpuid(0); let vendor_id: [[u8; 4]; 3] = [ebx.to_ne_bytes(), edx.to_ne_bytes(), ecx.to_ne_bytes()]; let vendor_id: [u8; 12] = mem::transmute(vendor_id); (max_basic_leaf, vendor_id) @@ -60,11 +54,8 @@ pub(crate) fn detect_features() -> cache::Initializer { // EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits"; // Contains information about most x86 features. - let CpuidResult { - ecx: proc_info_ecx, - edx: proc_info_edx, - .. - } = unsafe { __cpuid(0x0000_0001_u32) }; + let CpuidResult { ecx: proc_info_ecx, edx: proc_info_edx, .. } = + unsafe { __cpuid(0x0000_0001_u32) }; // EAX = 7: Queries "Extended Features"; // Contains information about bmi,bmi2, and avx2 support. @@ -76,11 +67,8 @@ pub(crate) fn detect_features() -> cache::Initializer { extended_features_edx_leaf_1, ) = if max_basic_leaf >= 7 { let CpuidResult { ebx, ecx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; - let CpuidResult { - eax: eax_1, - edx: edx_1, - .. - } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; + let CpuidResult { eax: eax_1, edx: edx_1, .. } = + unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; (ebx, ecx, edx, eax_1, edx_1) } else { (0, 0, 0, 0, 0) // CPUID does not support "Extended Features" @@ -89,10 +77,7 @@ pub(crate) fn detect_features() -> cache::Initializer { // EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported // - EAX returns the max leaf value for extended information, that is, // `cpuid` calls in range [0x8000_0000; u32::MAX]: - let CpuidResult { - eax: extended_max_basic_leaf, - .. - } = unsafe { __cpuid(0x8000_0000_u32) }; + let CpuidResult { eax: extended_max_basic_leaf, .. } = unsafe { __cpuid(0x8000_0000_u32) }; // EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature // Bits" @@ -208,10 +193,8 @@ pub(crate) fn detect_features() -> cache::Initializer { // Processor Extended State Enumeration Sub-leaf (EAX = 0DH, // ECX = 1): if max_basic_leaf >= 0xd { - let CpuidResult { - eax: proc_extended_state1_eax, - .. - } = unsafe { __cpuid_count(0xd_u32, 1) }; + let CpuidResult { eax: proc_extended_state1_eax, .. } = + unsafe { __cpuid_count(0xd_u32, 1) }; enable(proc_extended_state1_eax, 0, Feature::xsaveopt); enable(proc_extended_state1_eax, 1, Feature::xsavec); enable(proc_extended_state1_eax, 3, Feature::xsaves); @@ -269,10 +252,8 @@ pub(crate) fn detect_features() -> cache::Initializer { enable(extended_features_edx_leaf_1, 8, Feature::amx_complex); if max_basic_leaf >= 0x1e { - let CpuidResult { - eax: amx_feature_flags_eax, - .. - } = unsafe { __cpuid_count(0x1e_u32, 1) }; + let CpuidResult { eax: amx_feature_flags_eax, .. } = + unsafe { __cpuid_count(0x1e_u32, 1) }; enable(amx_feature_flags_eax, 4, Feature::amx_fp8); enable(amx_feature_flags_eax, 5, Feature::amx_transpose); diff --git a/library/std_detect/tests/cpu-detection.rs b/library/std_detect/tests/cpu-detection.rs index 7976aedc758..09a73572c1f 100644 --- a/library/std_detect/tests/cpu-detection.rs +++ b/library/std_detect/tests/cpu-detection.rs @@ -59,10 +59,7 @@ fn arm_linux() { } #[test] -#[cfg(all( - target_arch = "aarch64", - any(target_os = "linux", target_os = "android") -))] +#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))] fn aarch64_linux() { println!("asimd: {}", is_aarch64_feature_detected!("asimd")); println!("neon: {}", is_aarch64_feature_detected!("neon")); @@ -97,10 +94,7 @@ fn aarch64_linux() { println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes")); println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4")); println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3")); - println!( - "sve2-bitperm: {}", - is_aarch64_feature_detected!("sve2-bitperm") - ); + println!("sve2-bitperm: {}", is_aarch64_feature_detected!("sve2-bitperm")); println!("frintts: {}", is_aarch64_feature_detected!("frintts")); println!("i8mm: {}", is_aarch64_feature_detected!("i8mm")); println!("f32mm: {}", is_aarch64_feature_detected!("f32mm")); @@ -138,25 +132,13 @@ fn aarch64_linux() { println!("sme-lutv2: {}", is_aarch64_feature_detected!("sme-lutv2")); println!("sme-f8f16: {}", is_aarch64_feature_detected!("sme-f8f16")); println!("sme-f8f32: {}", is_aarch64_feature_detected!("sme-f8f32")); - println!( - "ssve-fp8fma: {}", - is_aarch64_feature_detected!("ssve-fp8fma") - ); - println!( - "ssve-fp8dot4: {}", - is_aarch64_feature_detected!("ssve-fp8dot4") - ); - println!( - "ssve-fp8dot2: {}", - is_aarch64_feature_detected!("ssve-fp8dot2") - ); + println!("ssve-fp8fma: {}", is_aarch64_feature_detected!("ssve-fp8fma")); + println!("ssve-fp8dot4: {}", is_aarch64_feature_detected!("ssve-fp8dot4")); + println!("ssve-fp8dot2: {}", is_aarch64_feature_detected!("ssve-fp8dot2")); } #[test] -#[cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - target_os = "windows" -))] +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_os = "windows"))] fn aarch64_windows() { println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); println!("fp: {:?}", is_aarch64_feature_detected!("fp")); @@ -171,10 +153,7 @@ fn aarch64_windows() { } #[test] -#[cfg(all( - target_arch = "aarch64", - any(target_os = "freebsd", target_os = "openbsd") -))] +#[cfg(all(target_arch = "aarch64", any(target_os = "freebsd", target_os = "openbsd")))] fn aarch64_bsd() { println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); @@ -236,14 +215,8 @@ fn riscv_linux() { println!("rv32e: {}", is_riscv_feature_detected!("rv32e")); println!("rv64i: {}", is_riscv_feature_detected!("rv64i")); println!("rv128i: {}", is_riscv_feature_detected!("rv128i")); - println!( - "unaligned-scalar-mem: {}", - is_riscv_feature_detected!("unaligned-scalar-mem") - ); - println!( - "unaligned-vector-mem: {}", - is_riscv_feature_detected!("unaligned-vector-mem") - ); + println!("unaligned-scalar-mem: {}", is_riscv_feature_detected!("unaligned-scalar-mem")); + println!("unaligned-vector-mem: {}", is_riscv_feature_detected!("unaligned-vector-mem")); println!("zicsr: {}", is_riscv_feature_detected!("zicsr")); println!("zicntr: {}", is_riscv_feature_detected!("zicntr")); println!("zihpm: {}", is_riscv_feature_detected!("zihpm")); @@ -336,10 +309,7 @@ fn powerpc_linux() { } #[test] -#[cfg(all( - target_arch = "powerpc64", - any(target_os = "linux", target_os = "freebsd"), -))] +#[cfg(all(target_arch = "powerpc64", any(target_os = "linux", target_os = "freebsd"),))] fn powerpc64_linux_or_freebsd() { println!("altivec: {}", is_powerpc64_feature_detected!("altivec")); println!("vsx: {}", is_powerpc64_feature_detected!("vsx")); diff --git a/library/std_detect/tests/x86-specific.rs b/library/std_detect/tests/x86-specific.rs index d9ec79821ba..2ed2bb2a99e 100644 --- a/library/std_detect/tests/x86-specific.rs +++ b/library/std_detect/tests/x86-specific.rs @@ -1,11 +1,6 @@ #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] #![allow(internal_features)] -#![feature( - stdarch_internal, - x86_amx_intrinsics, - xop_target_feature, - movrs_target_feature -)] +#![feature(stdarch_internal, x86_amx_intrinsics, xop_target_feature, movrs_target_feature)] #[macro_use] extern crate std_detect; @@ -40,24 +35,15 @@ fn dump() { println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl")); println!("avx512_ifma: {:?}", is_x86_feature_detected!("avx512ifma")); println!("avx512vbmi {:?}", is_x86_feature_detected!("avx512vbmi")); - println!( - "avx512_vpopcntdq: {:?}", - is_x86_feature_detected!("avx512vpopcntdq") - ); + println!("avx512_vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq")); println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2")); println!("gfni: {:?}", is_x86_feature_detected!("gfni")); println!("vaes: {:?}", is_x86_feature_detected!("vaes")); println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq")); println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni")); - println!( - "avx512bitalg: {:?}", - is_x86_feature_detected!("avx512bitalg") - ); + println!("avx512bitalg: {:?}", is_x86_feature_detected!("avx512bitalg")); println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16")); - println!( - "avx512vp2intersect: {:?}", - is_x86_feature_detected!("avx512vp2intersect") - ); + println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect")); println!("avx512fp16: {:?}", is_x86_feature_detected!("avx512fp16")); println!("fma: {:?}", is_x86_feature_detected!("fma")); println!("abm: {:?}", is_x86_feature_detected!("abm")); @@ -77,15 +63,9 @@ fn dump() { println!("movbe: {:?}", is_x86_feature_detected!("movbe")); println!("avxvnni: {:?}", is_x86_feature_detected!("avxvnni")); println!("avxvnniint8: {:?}", is_x86_feature_detected!("avxvnniint8")); - println!( - "avxneconvert: {:?}", - is_x86_feature_detected!("avxneconvert") - ); + println!("avxneconvert: {:?}", is_x86_feature_detected!("avxneconvert")); println!("avxifma: {:?}", is_x86_feature_detected!("avxifma")); - println!( - "avxvnniint16: {:?}", - is_x86_feature_detected!("avxvnniint16") - ); + println!("avxvnniint16: {:?}", is_x86_feature_detected!("avxvnniint16")); println!("amx-bf16: {:?}", is_x86_feature_detected!("amx-bf16")); println!("amx-tile: {:?}", is_x86_feature_detected!("amx-tile")); println!("amx-int8: {:?}", is_x86_feature_detected!("amx-int8")); @@ -96,10 +76,7 @@ fn dump() { println!("widekl: {:?}", is_x86_feature_detected!("widekl")); println!("movrs: {:?}", is_x86_feature_detected!("movrs")); println!("amx-fp8: {:?}", is_x86_feature_detected!("amx-fp8")); - println!( - "amx-transpose: {:?}", - is_x86_feature_detected!("amx-transpose") - ); + println!("amx-transpose: {:?}", is_x86_feature_detected!("amx-transpose")); println!("amx-tf32: {:?}", is_x86_feature_detected!("amx-tf32")); println!("amx-avx512: {:?}", is_x86_feature_detected!("amx-avx512")); println!("amx-movrs: {:?}", is_x86_feature_detected!("amx-movrs")); @@ -110,8 +87,5 @@ fn dump() { fn x86_deprecated() { println!("avx512gfni {:?}", is_x86_feature_detected!("avx512gfni")); println!("avx512vaes {:?}", is_x86_feature_detected!("avx512vaes")); - println!( - "avx512vpclmulqdq {:?}", - is_x86_feature_detected!("avx512vpclmulqdq") - ); + println!("avx512vpclmulqdq {:?}", is_x86_feature_detected!("avx512vpclmulqdq")); } -- cgit 1.4.1-3-g733a5 From 8dc2abb5c3a8de5982dd979ddaf722b4b6cc40fd Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 10:15:38 +0200 Subject: Update stdarch README --- library/stdarch/README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/stdarch/README.md b/library/stdarch/README.md index 9a35f4cd6ff..50905b49e80 100644 --- a/library/stdarch/README.md +++ b/library/stdarch/README.md @@ -4,16 +4,8 @@ stdarch - Rust's standard library SIMD components [![Actions Status](https://github.com/rust-lang/stdarch/workflows/CI/badge.svg)](https://github.com/rust-lang/stdarch/actions) -# Crates - -This repository contains two main crates: - -* [`core_arch`](crates/core_arch/README.md) implements `core::arch` - Rust's - core library architecture-specific intrinsics, and +This repository contains the [`core_arch`](crates/core_arch/README.md) crate, which implements `core::arch` - Rust's core library architecture-specific intrinsics. -* [`std_detect`](crates/std_detect/README.md) implements `std::detect` - Rust's - standard library run-time CPU feature detection. - The `std::simd` component now lives in the [`packed_simd_2`](https://github.com/rust-lang/packed_simd) crate. -- cgit 1.4.1-3-g733a5 From e07a1bbb79fc3fb400ac4a2f25bb37cd8a0c245b Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 10:23:36 +0200 Subject: Move tests around to appease `tidy` --- library/std_detect/src/detect/macros.rs | 2 +- library/std_detect/src/detect/os/linux/aarch64.rs | 82 +-------------- .../src/detect/os/linux/aarch64/tests.rs | 77 ++++++++++++++ library/std_detect/src/detect/os/linux/auxvec.rs | 114 +-------------------- .../std_detect/src/detect/os/linux/auxvec/tests.rs | 111 ++++++++++++++++++++ library/std_detect/src/detect/os/riscv.rs | 67 +----------- library/std_detect/src/detect/os/riscv/tests.rs | 64 ++++++++++++ src/tools/tidy/src/unit_tests.rs | 3 +- 8 files changed, 258 insertions(+), 262 deletions(-) create mode 100644 library/std_detect/src/detect/os/linux/aarch64/tests.rs create mode 100644 library/std_detect/src/detect/os/linux/auxvec/tests.rs create mode 100644 library/std_detect/src/detect/os/riscv/tests.rs diff --git a/library/std_detect/src/detect/macros.rs b/library/std_detect/src/detect/macros.rs index a2994fb7daa..c2a006d3753 100644 --- a/library/std_detect/src/detect/macros.rs +++ b/library/std_detect/src/detect/macros.rs @@ -131,7 +131,7 @@ macro_rules! features { }; } - #[test] + #[test] //tidy:skip #[deny(unexpected_cfgs)] #[deny(unfulfilled_lint_expectations)] fn unexpected_cfgs() { diff --git a/library/std_detect/src/detect/os/linux/aarch64.rs b/library/std_detect/src/detect/os/linux/aarch64.rs index 0de4beeae8b..87a9d6ebb88 100644 --- a/library/std_detect/src/detect/os/linux/aarch64.rs +++ b/library/std_detect/src/detect/os/linux/aarch64.rs @@ -395,84 +395,4 @@ impl AtHwcap { #[cfg(target_endian = "little")] #[cfg(test)] -mod tests { - use super::*; - - #[cfg(feature = "std_detect_file_io")] - mod auxv_from_file { - use super::auxvec::auxv_from_file; - use super::*; - // The baseline hwcaps used in the (artificial) auxv test files. - fn baseline_hwcaps() -> AtHwcap { - AtHwcap { - fp: true, - asimd: true, - aes: true, - pmull: true, - sha1: true, - sha2: true, - crc32: true, - atomics: true, - fphp: true, - asimdhp: true, - asimdrdm: true, - lrcpc: true, - dcpop: true, - asimddp: true, - ssbs: true, - ..AtHwcap::default() - } - } - - #[test] - fn linux_empty_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!( - AtHwcap::from(v), - AtHwcap { - // Some other HWCAP bits. - paca: true, - pacg: true, - // HWCAP2-only bits. - dcpodp: true, - frint: true, - rng: true, - bti: true, - mte: true, - ..baseline_hwcaps() - } - ); - } - } -} +mod tests; diff --git a/library/std_detect/src/detect/os/linux/aarch64/tests.rs b/library/std_detect/src/detect/os/linux/aarch64/tests.rs new file mode 100644 index 00000000000..a3562f2fd93 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/aarch64/tests.rs @@ -0,0 +1,77 @@ +use super::*; + +#[cfg(feature = "std_detect_file_io")] +mod auxv_from_file { + use super::auxvec::auxv_from_file; + use super::*; + // The baseline hwcaps used in the (artificial) auxv test files. + fn baseline_hwcaps() -> AtHwcap { + AtHwcap { + fp: true, + asimd: true, + aes: true, + pmull: true, + sha1: true, + sha2: true, + crc32: true, + atomics: true, + fphp: true, + asimdhp: true, + asimdrdm: true, + lrcpc: true, + dcpop: true, + asimddp: true, + ssbs: true, + ..AtHwcap::default() + } + } + + #[test] + fn linux_empty_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); + } + #[test] + fn linux_no_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); + } + #[test] + fn linux_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!( + AtHwcap::from(v), + AtHwcap { + // Some other HWCAP bits. + paca: true, + pacg: true, + // HWCAP2-only bits. + dcpodp: true, + frint: true, + rng: true, + bti: true, + mte: true, + ..baseline_hwcaps() + } + ); + } +} diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs index 54f52aa7533..1ed395f45b9 100644 --- a/library/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -226,116 +226,4 @@ fn auxv_from_buf(buf: &[usize]) -> Result { } #[cfg(test)] -mod tests { - use super::*; - - // FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv - // does not always contain the AT_HWCAP key under qemu. - #[cfg(any( - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - #[test] - fn auxv_crate() { - let v = auxv(); - if let Ok(hwcap) = getauxval(AT_HWCAP) { - let rt_hwcap = v.expect("failed to find hwcap key").hwcap; - assert_eq!(rt_hwcap, hwcap); - } - - // Targets with AT_HWCAP and AT_HWCAP2: - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - { - if let Ok(hwcap2) = getauxval(AT_HWCAP2) { - let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2; - assert_eq!(rt_hwcap2, hwcap2); - } - } - } - - #[test] - fn auxv_dump() { - if let Ok(auxvec) = auxv() { - println!("{:?}", auxvec); - } else { - println!("both getauxval() and reading /proc/self/auxv failed!"); - } - } - - #[cfg(feature = "std_detect_file_io")] - cfg_if::cfg_if! { - if #[cfg(target_arch = "arm")] { - #[test] - fn linux_rpi3() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - assert_eq!(v.hwcap, 4174038); - assert_eq!(v.hwcap2, 16); - } - - #[test] - fn linux_macos_vb() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv"); - println!("file: {file}"); - // The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero. - let v = auxv_from_file(file).unwrap(); - assert_eq!(v.hwcap, 126614527); - assert_eq!(v.hwcap2, 0); - } - } else if #[cfg(target_arch = "aarch64")] { - #[cfg(target_endian = "little")] - #[test] - fn linux_artificial_aarch64() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - assert_eq!(v.hwcap, 0x0123456789abcdef); - assert_eq!(v.hwcap2, 0x02468ace13579bdf); - } - #[cfg(target_endian = "little")] - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - // An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP. - assert_ne!(v.hwcap, 0); - assert_eq!(v.hwcap2, 0); - } - } - } - - #[test] - #[cfg(feature = "std_detect_file_io")] - fn auxv_dump_procfs() { - if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { - println!("{:?}", auxvec); - } else { - println!("reading /proc/self/auxv failed!"); - } - } - - #[cfg(any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - ))] - #[test] - #[cfg(feature = "std_detect_file_io")] - fn auxv_crate_procfs() { - if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { - assert_eq!(auxv().unwrap(), procfs_auxv); - } - } -} +mod tests; diff --git a/library/std_detect/src/detect/os/linux/auxvec/tests.rs b/library/std_detect/src/detect/os/linux/auxvec/tests.rs new file mode 100644 index 00000000000..c0e0ae12a05 --- /dev/null +++ b/library/std_detect/src/detect/os/linux/auxvec/tests.rs @@ -0,0 +1,111 @@ +use super::*; + +// FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv +// does not always contain the AT_HWCAP key under qemu. +#[cfg(any( + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", +))] +#[test] +fn auxv_crate() { + let v = auxv(); + if let Ok(hwcap) = getauxval(AT_HWCAP) { + let rt_hwcap = v.expect("failed to find hwcap key").hwcap; + assert_eq!(rt_hwcap, hwcap); + } + + // Targets with AT_HWCAP and AT_HWCAP2: + #[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + ))] + { + if let Ok(hwcap2) = getauxval(AT_HWCAP2) { + let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2; + assert_eq!(rt_hwcap2, hwcap2); + } + } +} + +#[test] +fn auxv_dump() { + if let Ok(auxvec) = auxv() { + println!("{:?}", auxvec); + } else { + println!("both getauxval() and reading /proc/self/auxv failed!"); + } +} + +#[cfg(feature = "std_detect_file_io")] +cfg_if::cfg_if! { + if #[cfg(target_arch = "arm")] { + #[test] + fn linux_rpi3() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + assert_eq!(v.hwcap, 4174038); + assert_eq!(v.hwcap2, 16); + } + + #[test] + fn linux_macos_vb() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv"); + println!("file: {file}"); + // The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero. + let v = auxv_from_file(file).unwrap(); + assert_eq!(v.hwcap, 126614527); + assert_eq!(v.hwcap2, 0); + } + } else if #[cfg(target_arch = "aarch64")] { + #[cfg(target_endian = "little")] + #[test] + fn linux_artificial_aarch64() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + assert_eq!(v.hwcap, 0x0123456789abcdef); + assert_eq!(v.hwcap2, 0x02468ace13579bdf); + } + #[cfg(target_endian = "little")] + #[test] + fn linux_no_hwcap2_aarch64() { + let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + // An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP. + assert_ne!(v.hwcap, 0); + assert_eq!(v.hwcap2, 0); + } + } +} + +#[test] +#[cfg(feature = "std_detect_file_io")] +fn auxv_dump_procfs() { + if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { + println!("{:?}", auxvec); + } else { + println!("reading /proc/self/auxv failed!"); + } +} + +#[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", +))] +#[test] +#[cfg(feature = "std_detect_file_io")] +fn auxv_crate_procfs() { + if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { + assert_eq!(auxv().unwrap(), procfs_auxv); + } +} diff --git a/library/std_detect/src/detect/os/riscv.rs b/library/std_detect/src/detect/os/riscv.rs index 4c59ede8029..46b7dd71eb3 100644 --- a/library/std_detect/src/detect/os/riscv.rs +++ b/library/std_detect/src/detect/os/riscv.rs @@ -135,69 +135,4 @@ pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initialize } #[cfg(test)] -mod tests { - use super::*; - - #[test] - fn simple_direct() { - let mut value = cache::Initializer::default(); - value.set(Feature::f as u32); - // F (and other extensions with CSRs) -> Zicsr - assert!(imply_features(value).test(Feature::zicsr as u32)); - } - - #[test] - fn simple_indirect() { - let mut value = cache::Initializer::default(); - value.set(Feature::q as u32); - // Q -> D, D -> F, F -> Zicsr - assert!(imply_features(value).test(Feature::zicsr as u32)); - } - - #[test] - fn complex_zcd() { - let mut value = cache::Initializer::default(); - // C & D -> Zcd - value.set(Feature::c as u32); - assert!(!imply_features(value).test(Feature::zcd as u32)); - value.set(Feature::d as u32); - assert!(imply_features(value).test(Feature::zcd as u32)); - } - - #[test] - fn group_simple_forward() { - let mut value = cache::Initializer::default(); - // A -> Zalrsc & Zaamo (forward implication) - value.set(Feature::a as u32); - let value = imply_features(value); - assert!(value.test(Feature::zalrsc as u32)); - assert!(value.test(Feature::zaamo as u32)); - } - - #[test] - fn group_simple_backward() { - let mut value = cache::Initializer::default(); - // Zalrsc & Zaamo -> A (reverse implication) - value.set(Feature::zalrsc as u32); - value.set(Feature::zaamo as u32); - assert!(imply_features(value).test(Feature::a as u32)); - } - - #[test] - fn group_complex_convergence() { - let mut value = cache::Initializer::default(); - // Needs 3 iterations to converge - // (and 4th iteration for convergence checking): - // 1. [Zvksc] -> Zvks & Zvbc - // 2. Zvks -> Zvksed & Zvksh & Zvkb & Zvkt - // 3a. [Zvkned] & [Zvknhb] & [Zvkb] & Zvkt -> {Zvkn} - // 3b. Zvkn & Zvbc -> {Zvknc} - value.set(Feature::zvksc as u32); - value.set(Feature::zvkned as u32); - value.set(Feature::zvknhb as u32); - value.set(Feature::zvkb as u32); - let value = imply_features(value); - assert!(value.test(Feature::zvkn as u32)); - assert!(value.test(Feature::zvknc as u32)); - } -} +mod tests; diff --git a/library/std_detect/src/detect/os/riscv/tests.rs b/library/std_detect/src/detect/os/riscv/tests.rs new file mode 100644 index 00000000000..99a81dee05a --- /dev/null +++ b/library/std_detect/src/detect/os/riscv/tests.rs @@ -0,0 +1,64 @@ +use super::*; + +#[test] +fn simple_direct() { + let mut value = cache::Initializer::default(); + value.set(Feature::f as u32); + // F (and other extensions with CSRs) -> Zicsr + assert!(imply_features(value).test(Feature::zicsr as u32)); +} + +#[test] +fn simple_indirect() { + let mut value = cache::Initializer::default(); + value.set(Feature::q as u32); + // Q -> D, D -> F, F -> Zicsr + assert!(imply_features(value).test(Feature::zicsr as u32)); +} + +#[test] +fn complex_zcd() { + let mut value = cache::Initializer::default(); + // C & D -> Zcd + value.set(Feature::c as u32); + assert!(!imply_features(value).test(Feature::zcd as u32)); + value.set(Feature::d as u32); + assert!(imply_features(value).test(Feature::zcd as u32)); +} + +#[test] +fn group_simple_forward() { + let mut value = cache::Initializer::default(); + // A -> Zalrsc & Zaamo (forward implication) + value.set(Feature::a as u32); + let value = imply_features(value); + assert!(value.test(Feature::zalrsc as u32)); + assert!(value.test(Feature::zaamo as u32)); +} + +#[test] +fn group_simple_backward() { + let mut value = cache::Initializer::default(); + // Zalrsc & Zaamo -> A (reverse implication) + value.set(Feature::zalrsc as u32); + value.set(Feature::zaamo as u32); + assert!(imply_features(value).test(Feature::a as u32)); +} + +#[test] +fn group_complex_convergence() { + let mut value = cache::Initializer::default(); + // Needs 3 iterations to converge + // (and 4th iteration for convergence checking): + // 1. [Zvksc] -> Zvks & Zvbc + // 2. Zvks -> Zvksed & Zvksh & Zvkb & Zvkt + // 3a. [Zvkned] & [Zvknhb] & [Zvkb] & Zvkt -> {Zvkn} + // 3b. Zvkn & Zvbc -> {Zvknc} + value.set(Feature::zvksc as u32); + value.set(Feature::zvkned as u32); + value.set(Feature::zvknhb as u32); + value.set(Feature::zvkb as u32); + let value = imply_features(value); + assert!(value.test(Feature::zvkn as u32)); + assert!(value.test(Feature::zvknc as u32)); +} diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs index 90ef36d5882..df9146b5147 100644 --- a/src/tools/tidy/src/unit_tests.rs +++ b/src/tools/tidy/src/unit_tests.rs @@ -56,7 +56,8 @@ pub fn check(root_path: &Path, bad: &mut bool) { let line = line.trim(); let is_test = || line.contains("#[test]") && !line.contains("`#[test]"); let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]"); - if !line.starts_with("//") && (is_test() || is_bench()) { + let manual_skip = line.contains("//tidy:skip"); + if !line.starts_with("//") && (is_test() || is_bench()) && !manual_skip { let explanation = if is_core { "`core` unit tests and benchmarks must be placed into `coretests`" } else if is_alloc { -- cgit 1.4.1-3-g733a5 From ffa97a647e3786add894093aa2cc7561c7c64607 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 4 Jul 2025 15:25:28 +0200 Subject: Fix warning --- library/std_detect/tests/cpu-detection.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std_detect/tests/cpu-detection.rs b/library/std_detect/tests/cpu-detection.rs index 09a73572c1f..5ad32d83237 100644 --- a/library/std_detect/tests/cpu-detection.rs +++ b/library/std_detect/tests/cpu-detection.rs @@ -27,6 +27,16 @@ ), macro_use )] +#[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + target_arch = "arm64ec", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", +))] extern crate std_detect; #[test] -- cgit 1.4.1-3-g733a5 From 608297247a776a32c4aca08f1784caca8a3c33e8 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Sun, 13 Jul 2025 13:08:17 +0200 Subject: Remove `std_detect` from stdarch examples --- library/stdarch/Cargo.lock | 23 ----------------------- library/stdarch/examples/Cargo.toml | 1 - library/stdarch/examples/connect5.rs | 16 ++++++++++++---- library/stdarch/examples/hex.rs | 8 ++++++-- 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/library/stdarch/Cargo.lock b/library/stdarch/Cargo.lock index 4806682e6e0..21ce304db0d 100644 --- a/library/stdarch/Cargo.lock +++ b/library/stdarch/Cargo.lock @@ -580,18 +580,6 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" -[[package]] -name = "rustc-std-workspace-alloc" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3" - -[[package]] -name = "rustc-std-workspace-core" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" - [[package]] name = "ryu" version = "1.0.20" @@ -694,16 +682,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "std_detect" -version = "0.1.5" -dependencies = [ - "cfg-if", - "libc", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "stdarch-gen-arm" version = "0.1.0" @@ -756,7 +734,6 @@ dependencies = [ "core_arch", "quickcheck", "rand", - "std_detect", ] [[package]] diff --git a/library/stdarch/examples/Cargo.toml b/library/stdarch/examples/Cargo.toml index 61184494e15..61451edee84 100644 --- a/library/stdarch/examples/Cargo.toml +++ b/library/stdarch/examples/Cargo.toml @@ -12,7 +12,6 @@ default-run = "hex" [dependencies] core_arch = { path = "../crates/core_arch" } -std_detect = { path = "../crates/std_detect" } quickcheck = "1.0" rand = "0.8" diff --git a/library/stdarch/examples/connect5.rs b/library/stdarch/examples/connect5.rs index 1d8e0f0990a..371b28552b3 100644 --- a/library/stdarch/examples/connect5.rs +++ b/library/stdarch/examples/connect5.rs @@ -40,9 +40,13 @@ use std::cmp; use std::time::Instant; #[cfg(target_arch = "x86")] -use {core_arch::arch::x86::*, std_detect::is_x86_feature_detected}; +use core_arch::arch::x86::*; #[cfg(target_arch = "x86_64")] -use {core_arch::arch::x86_64::*, std_detect::is_x86_feature_detected}; +use core_arch::arch::x86_64::*; +#[cfg(target_arch = "x86")] +use std::is_x86_feature_detected; +#[cfg(target_arch = "x86_64")] +use std::is_x86_feature_detected; // types @@ -558,8 +562,12 @@ fn search(pos: &Pos, alpha: i32, beta: i32, depth: i32, _ply: i32) -> i32 { assert_ne!(bm, MOVE_NONE); assert!(bs >= -EVAL_INF && bs <= EVAL_INF); - // best move at the root node, best score elsewhere - if _ply == 0 { bm } else { bs } + //best move at the root node, best score elsewhere + if _ply == 0 { + bm + } else { + bs + } } /// Evaluation function: give different scores to different patterns after a fixed depth. diff --git a/library/stdarch/examples/hex.rs b/library/stdarch/examples/hex.rs index e393ad72716..95ffbaf666c 100644 --- a/library/stdarch/examples/hex.rs +++ b/library/stdarch/examples/hex.rs @@ -36,9 +36,13 @@ use std::{ }; #[cfg(target_arch = "x86")] -use {core_arch::arch::x86::*, std_detect::is_x86_feature_detected}; +use core_arch::arch::x86::*; #[cfg(target_arch = "x86_64")] -use {core_arch::arch::x86_64::*, std_detect::is_x86_feature_detected}; +use core_arch::arch::x86_64::*; +#[cfg(target_arch = "x86")] +use std::is_x86_feature_detected; +#[cfg(target_arch = "x86_64")] +use std::is_x86_feature_detected; fn main() { let mut input = Vec::new(); -- cgit 1.4.1-3-g733a5 From 847f8db5ad2d3b369ce97935dd770a15280ddf96 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Sun, 13 Jul 2025 13:41:22 +0200 Subject: Remove `std_detect` from stdarch's CI --- library/stdarch/.github/workflows/main.yml | 13 +-------- library/stdarch/ci/build-std-detect.sh | 46 ------------------------------ library/stdarch/ci/dox.sh | 3 -- library/stdarch/ci/run-docker.sh | 1 - library/stdarch/ci/run.sh | 10 +------ 5 files changed, 2 insertions(+), 71 deletions(-) delete mode 100755 library/stdarch/ci/build-std-detect.sh diff --git a/library/stdarch/.github/workflows/main.yml b/library/stdarch/.github/workflows/main.yml index 59aad0b5d01..048ce986460 100644 --- a/library/stdarch/.github/workflows/main.yml +++ b/library/stdarch/.github/workflows/main.yml @@ -258,7 +258,7 @@ jobs: # Check that the generated files agree with the checked-in versions. check-stdarch-gen: needs: [style] - name: Check stdarch-gen-{arm, loongarch} output + name: Check stdarch-gen-{arm, loongarch} output runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -277,22 +277,11 @@ jobs: cargo run --bin=stdarch-gen-loongarch --release -- crates/stdarch-gen-loongarch/lasx.spec git diff --exit-code - build-std-detect: - needs: [style] - name: Build std_detect - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Install Rust - run: rustup update nightly && rustup default nightly - - run: ./ci/build-std-detect.sh - conclusion: needs: - docs - verify - test - - build-std-detect - check-stdarch-gen runs-on: ubuntu-latest # We need to ensure this job does *not* get skipped if its dependencies fail, diff --git a/library/stdarch/ci/build-std-detect.sh b/library/stdarch/ci/build-std-detect.sh deleted file mode 100755 index e79a497cc35..00000000000 --- a/library/stdarch/ci/build-std-detect.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -# Build std_detect on non-Linux & non-x86 targets. -# -# In std_detect, non-x86 targets have OS-specific implementations, -# but we can test only Linux in CI. This script builds targets supported -# by std_detect but cannot be tested in CI. - -set -ex -cd "$(dirname "$0")"/.. - -targets=( - # Linux - aarch64-unknown-linux-musl - armv5te-unknown-linux-musleabi - aarch64-unknown-linux-ohos - armv7-unknown-linux-ohos - - # Android - aarch64-linux-android - arm-linux-androideabi - - # FreeBSD - aarch64-unknown-freebsd - armv6-unknown-freebsd - powerpc-unknown-freebsd - powerpc64-unknown-freebsd - - # OpenBSD - aarch64-unknown-openbsd - - # Windows - aarch64-pc-windows-msvc -) - -rustup component add rust-src # for -Z build-std - -cd crates/std_detect -for target in "${targets[@]}"; do - if rustup target add "${target}" &>/dev/null; then - cargo build --target "${target}" - else - # tier 3 targets requires -Z build-std. - cargo build -Z build-std="core,alloc" --target "${target}" - fi -done diff --git a/library/stdarch/ci/dox.sh b/library/stdarch/ci/dox.sh index 910265fad84..94d76d43047 100755 --- a/library/stdarch/ci/dox.sh +++ b/library/stdarch/ci/dox.sh @@ -16,10 +16,7 @@ dox() { cargo clean --target "${1}" cargo build --verbose --target "${1}" --manifest-path crates/core_arch/Cargo.toml - cargo build --verbose --target "${1}" --manifest-path crates/std_detect/Cargo.toml - cargo doc --verbose --target "${1}" --manifest-path crates/core_arch/Cargo.toml - cargo doc --verbose --target "${1}" --manifest-path crates/std_detect/Cargo.toml } if [ -z "$1" ]; then diff --git a/library/stdarch/ci/run-docker.sh b/library/stdarch/ci/run-docker.sh index 657353004dc..d7aa50a8c96 100755 --- a/library/stdarch/ci/run-docker.sh +++ b/library/stdarch/ci/run-docker.sh @@ -37,7 +37,6 @@ run() { --env NORUN \ --env RUSTFLAGS \ --env CARGO_UNSTABLE_BUILD_STD \ - --env RUST_STD_DETECT_UNSTABLE \ --volume "${HOME}/.cargo":/cargo \ --volume "$(rustc --print sysroot)":/rust:ro \ --volume "$(pwd)":/checkout:ro \ diff --git a/library/stdarch/ci/run.sh b/library/stdarch/ci/run.sh index 78a808b46a0..aa4479395d5 100755 --- a/library/stdarch/ci/run.sh +++ b/library/stdarch/ci/run.sh @@ -78,20 +78,12 @@ cargo_test() { } CORE_ARCH="--manifest-path=crates/core_arch/Cargo.toml" -STD_DETECT="--manifest-path=crates/std_detect/Cargo.toml" STDARCH_EXAMPLES="--manifest-path=examples/Cargo.toml" INTRINSIC_TEST="--manifest-path=crates/intrinsic-test/Cargo.toml" cargo_test "${CORE_ARCH} ${PROFILE}" if [ "$NOSTD" != "1" ]; then - cargo_test "${STD_DETECT} ${PROFILE}" - - cargo_test "${STD_DETECT} --no-default-features" - cargo_test "${STD_DETECT} --no-default-features --features=std_detect_file_io" - cargo_test "${STD_DETECT} --no-default-features --features=std_detect_dlsym_getauxval" - cargo_test "${STD_DETECT} --no-default-features --features=std_detect_dlsym_getauxval,std_detect_file_io" - cargo_test "${STDARCH_EXAMPLES} ${PROFILE}" fi @@ -139,7 +131,7 @@ case ${TARGET} in cargo_test "${PROFILE}" ;; - # Setup aarch64 & armv7 specific variables, the runner, along with some + # Setup aarch64 & armv7 specific variables, the runner, along with some # tests to skip aarch64-unknown-linux-gnu*) TEST_CPPFLAGS="-fuse-ld=lld -I/usr/aarch64-linux-gnu/include/ -I/usr/aarch64-linux-gnu/include/c++/9/aarch64-linux-gnu/" -- cgit 1.4.1-3-g733a5 From cbd9fe012acad68ce8ea2cb90b23589cd2bb0c31 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Sun, 13 Jul 2025 14:37:28 +0200 Subject: Bless bootstrap tests --- src/bootstrap/src/core/builder/tests.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 105d4229e75..6ea5d4e6553 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -999,7 +999,7 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustdoc 0 - [doc] std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] "); } @@ -1048,7 +1048,7 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 @@ -1090,7 +1090,7 @@ mod snapshot { [build] rustc 1 -> WasmComponentLd 2 [build] rustc 1 -> LlvmBitcodeLinker 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 @@ -1126,8 +1126,8 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 @@ -1163,7 +1163,7 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 1 -> std 1 @@ -1200,8 +1200,8 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 1 -> std 1 @@ -1242,7 +1242,7 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> RustInstaller 1 [dist] docs @@ -1274,7 +1274,7 @@ mod snapshot { [build] rustc 1 -> rustc 2 [build] rustc 1 -> WasmComponentLd 2 [build] rustdoc 1 - [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 @@ -1620,7 +1620,7 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustdoc 0 - [doc] std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind] "); } -- cgit 1.4.1-3-g733a5 From 5e52677a82c6c146469561c97ca4c63a75242102 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Mon, 14 Jul 2025 21:57:08 +0200 Subject: Remove licenses from std-detect They are subsumed by the main repo licenses. --- library/std_detect/LICENSE-APACHE | 201 -------------------------------------- library/std_detect/LICENSE-MIT | 25 ----- 2 files changed, 226 deletions(-) delete mode 100644 library/std_detect/LICENSE-APACHE delete mode 100644 library/std_detect/LICENSE-MIT diff --git a/library/std_detect/LICENSE-APACHE b/library/std_detect/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e8..00000000000 --- a/library/std_detect/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/library/std_detect/LICENSE-MIT b/library/std_detect/LICENSE-MIT deleted file mode 100644 index 52d82415d8b..00000000000 --- a/library/std_detect/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2017 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -- cgit 1.4.1-3-g733a5 From 81d90d8257e59bc27acd6ec98f3cce3d27de6755 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 18 Jul 2025 08:49:28 +0200 Subject: Improve error messages of auxv loading --- library/std_detect/src/detect/os/linux/auxvec.rs | 17 +++++++++++------ library/std_detect/src/detect/os/linux/mod.rs | 10 ++++++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs index 1ed395f45b9..443caaaa186 100644 --- a/library/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -119,7 +119,7 @@ pub(crate) fn auxv() -> Result { { // If calling getauxval fails, try to read the auxiliary vector from // its file: - auxv_from_file("/proc/self/auxv") + auxv_from_file("/proc/self/auxv").map_err(|_| ()) } #[cfg(not(feature = "std_detect_file_io"))] { @@ -157,17 +157,22 @@ fn getauxval(key: usize) -> Result { /// Tries to read the auxiliary vector from the `file`. If this fails, this /// function returns `Err`. #[cfg(feature = "std_detect_file_io")] -pub(super) fn auxv_from_file(file: &str) -> Result { +pub(super) fn auxv_from_file(file: &str) -> Result { let file = super::read_file(file)?; + auxv_from_file_bytes(&file) +} +/// Read auxiliary vector from a slice of bytes. +#[cfg(feature = "std_detect_file_io")] +pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result { // See . // // The auxiliary vector contains at most 34 (key,value) fields: from // `AT_MINSIGSTKSZ` to `AT_NULL`, but its number may increase. - let len = file.len(); + let len = bytes.len(); let mut buf = alloc::vec![0_usize; 1 + len / core::mem::size_of::()]; unsafe { - core::ptr::copy_nonoverlapping(file.as_ptr(), buf.as_mut_ptr() as *mut u8, len); + core::ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr() as *mut u8, len); } auxv_from_buf(&buf) @@ -176,7 +181,7 @@ pub(super) fn auxv_from_file(file: &str) -> Result { /// Tries to interpret the `buffer` as an auxiliary vector. If that fails, this /// function returns `Err`. #[cfg(feature = "std_detect_file_io")] -fn auxv_from_buf(buf: &[usize]) -> Result { +fn auxv_from_buf(buf: &[usize]) -> Result { // Targets with only AT_HWCAP: #[cfg(any( target_arch = "riscv32", @@ -222,7 +227,7 @@ fn auxv_from_buf(buf: &[usize]) -> Result { } // Suppress unused variable let _ = buf; - Err(()) + Err(alloc::string::String::from("hwcap not found")) } #[cfg(test)] diff --git a/library/std_detect/src/detect/os/linux/mod.rs b/library/std_detect/src/detect/os/linux/mod.rs index 9accd41717b..5ae2aaeab5b 100644 --- a/library/std_detect/src/detect/os/linux/mod.rs +++ b/library/std_detect/src/detect/os/linux/mod.rs @@ -6,14 +6,16 @@ use alloc::vec::Vec; mod auxvec; #[cfg(feature = "std_detect_file_io")] -fn read_file(path: &str) -> Result, ()> { - let mut path = Vec::from(path.as_bytes()); +fn read_file(orig_path: &str) -> Result, alloc::string::String> { + use alloc::format; + + let mut path = Vec::from(orig_path.as_bytes()); path.push(0); unsafe { let file = libc::open(path.as_ptr() as *const libc::c_char, libc::O_RDONLY); if file == -1 { - return Err(()); + return Err(format!("Cannot open file at {orig_path}")); } let mut data = Vec::new(); @@ -23,7 +25,7 @@ fn read_file(path: &str) -> Result, ()> { match libc::read(file, spare.as_mut_ptr() as *mut _, spare.len()) { -1 => { libc::close(file); - return Err(()); + return Err(format!("Error while reading from file at {orig_path}")); } 0 => break, n => data.set_len(data.len() + n as usize), -- cgit 1.4.1-3-g733a5 From 9a1179c4de485759d8d8f3bf978e26fc4e86af64 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 18 Jul 2025 08:49:59 +0200 Subject: Embed auxv files directly into the test binary --- .../std_detect/src/detect/os/linux/auxvec/tests.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/library/std_detect/src/detect/os/linux/auxvec/tests.rs b/library/std_detect/src/detect/os/linux/auxvec/tests.rs index c0e0ae12a05..536615fa272 100644 --- a/library/std_detect/src/detect/os/linux/auxvec/tests.rs +++ b/library/std_detect/src/detect/os/linux/auxvec/tests.rs @@ -44,21 +44,21 @@ fn auxv_dump() { #[cfg(feature = "std_detect_file_io")] cfg_if::cfg_if! { if #[cfg(target_arch = "arm")] { + // The tests below can be executed under qemu, where we do not have access to the test + // files on disk, so we need to embed them with `include_bytes!`. #[test] fn linux_rpi3() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); + let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv")); + let v = auxv_from_file_bytes(auxv).unwrap(); assert_eq!(v.hwcap, 4174038); assert_eq!(v.hwcap2, 16); } #[test] fn linux_macos_vb() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv"); - println!("file: {file}"); + let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv")); // The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero. - let v = auxv_from_file(file).unwrap(); + let v = auxv_from_file_bytes(auxv).unwrap(); assert_eq!(v.hwcap, 126614527); assert_eq!(v.hwcap2, 0); } @@ -66,18 +66,16 @@ cfg_if::cfg_if! { #[cfg(target_endian = "little")] #[test] fn linux_artificial_aarch64() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); + let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv")); + let v = auxv_from_file_bytes(auxv).unwrap(); assert_eq!(v.hwcap, 0x0123456789abcdef); assert_eq!(v.hwcap2, 0x02468ace13579bdf); } #[cfg(target_endian = "little")] #[test] fn linux_no_hwcap2_aarch64() { - let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); + let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv")); + let v = auxv_from_file_bytes(auxv).unwrap(); // An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP. assert_ne!(v.hwcap, 0); assert_eq!(v.hwcap2, 0); -- cgit 1.4.1-3-g733a5